mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 02:48:14 -05:00
Update #0 - First Release
This commit is contained in:
@ -0,0 +1,163 @@
|
||||
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.teavm.WebGLQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLVertexArray;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
class OpenGLObjects {
|
||||
|
||||
static class BufferGL implements IBufferGL {
|
||||
|
||||
final WebGLBuffer ptr;
|
||||
|
||||
BufferGL(WebGLBuffer ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteBuffers(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class BufferArrayGL implements IBufferArrayGL {
|
||||
|
||||
final WebGLVertexArray ptr;
|
||||
|
||||
BufferArrayGL(WebGLVertexArray ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteVertexArrays(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TextureGL implements ITextureGL {
|
||||
|
||||
final WebGLTexture ptr;
|
||||
|
||||
TextureGL(WebGLTexture ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteTextures(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ProgramGL implements IProgramGL {
|
||||
|
||||
final WebGLProgram ptr;
|
||||
|
||||
ProgramGL(WebGLProgram ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteProgram(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class UniformGL implements IUniformGL {
|
||||
|
||||
final WebGLUniformLocation ptr;
|
||||
|
||||
UniformGL(WebGLUniformLocation ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ShaderGL implements IShaderGL {
|
||||
|
||||
final WebGLShader ptr;
|
||||
|
||||
ShaderGL(WebGLShader ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteShader(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FramebufferGL implements IFramebufferGL {
|
||||
|
||||
final WebGLFramebuffer ptr;
|
||||
|
||||
FramebufferGL(WebGLFramebuffer ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteFramebuffer(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class RenderbufferGL implements IRenderbufferGL {
|
||||
|
||||
final WebGLRenderbuffer ptr;
|
||||
|
||||
RenderbufferGL(WebGLRenderbuffer ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteRenderbuffer(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class QueryGL implements IQueryGL {
|
||||
|
||||
final WebGLQuery ptr;
|
||||
|
||||
QueryGL(WebGLQuery ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteQueries(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,235 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.browser.Storage;
|
||||
import org.teavm.jso.browser.TimerHandler;
|
||||
import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.canvas.CanvasRenderingContext2D;
|
||||
import org.teavm.jso.dom.events.Event;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.dom.html.HTMLCanvasElement;
|
||||
import org.teavm.jso.dom.html.HTMLInputElement;
|
||||
import org.teavm.jso.dom.xml.Document;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Int8Array;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Base64;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformApplication {
|
||||
|
||||
public static void openLink(String url) {
|
||||
Window.current().open(url, "_blank");
|
||||
}
|
||||
|
||||
public static void setClipboard(String text) {
|
||||
try {
|
||||
setClipboard0(text);
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("Exception setting clipboard data");
|
||||
}
|
||||
}
|
||||
|
||||
public static String getClipboard() {
|
||||
try {
|
||||
return getClipboard0();
|
||||
}catch(Throwable t) {
|
||||
PlatformRuntime.logger.error("Exception getting clipboard data");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface StupidFunctionResolveString extends JSObject {
|
||||
void resolveStr(String s);
|
||||
}
|
||||
|
||||
@Async
|
||||
private static native String getClipboard0();
|
||||
|
||||
private static void getClipboard0(final AsyncCallback<String> cb) {
|
||||
final long start = System.currentTimeMillis();
|
||||
getClipboard1(new StupidFunctionResolveString() {
|
||||
@Override
|
||||
public void resolveStr(String s) {
|
||||
if(System.currentTimeMillis() - start > 500l) {
|
||||
PlatformInput.unpressCTRL = true;
|
||||
}
|
||||
cb.complete(s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@JSBody(params = { "cb" }, script = "if(!window.navigator.clipboard) cb(\"\"); else window.navigator.clipboard.readText().then(function(s) { cb(s); }, function(s) { cb(\"\"); });")
|
||||
private static native void getClipboard1(StupidFunctionResolveString cb);
|
||||
|
||||
@JSBody(params = { "str" }, script = "if(window.navigator.clipboard) window.navigator.clipboard.writeText(str);")
|
||||
private static native void setClipboard0(String str);
|
||||
|
||||
public static void setLocalStorage(String name, byte[] data) {
|
||||
try {
|
||||
Storage s = Window.current().getLocalStorage();
|
||||
if(s != null) {
|
||||
s.setItem("_eaglercraftX." + name, Base64.encodeBase64String(data));
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] getLocalStorage(String name) {
|
||||
try {
|
||||
Storage s = Window.current().getLocalStorage();
|
||||
if(s != null) {
|
||||
String str = s.getItem("_eaglercraftX." + name);
|
||||
if(str != null) {
|
||||
return Base64.decodeBase64(str);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final DateFormat dateFormatSS = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
|
||||
|
||||
public static String saveScreenshot() {
|
||||
String name = "screenshot_" + dateFormatSS.format(new Date()).toString() + ".png";
|
||||
int w = PlatformRuntime.canvas.getWidth();
|
||||
int h = PlatformRuntime.canvas.getHeight();
|
||||
HTMLCanvasElement copyCanvas = (HTMLCanvasElement) Window.current().getDocument().createElement("canvas");
|
||||
copyCanvas.setWidth(w);
|
||||
copyCanvas.setHeight(h);
|
||||
CanvasRenderingContext2D ctx = (CanvasRenderingContext2D) copyCanvas.getContext("2d");
|
||||
ctx.drawImage(PlatformRuntime.canvas, 0, 0);
|
||||
saveScreenshot(name, copyCanvas);
|
||||
return name;
|
||||
}
|
||||
|
||||
@JSBody(params = { "name", "cvs" }, script = "var a=document.createElement(\"a\");a.href=cvs.toDataURL(\"image/png\");a.download=name;a.click();")
|
||||
private static native void saveScreenshot(String name, HTMLCanvasElement cvs);
|
||||
|
||||
public static void showPopup(final String msg) {
|
||||
Window.setTimeout(new TimerHandler() {
|
||||
@Override
|
||||
public void onTimer() {
|
||||
Window.alert(msg);
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface FileChooserCallback extends JSObject {
|
||||
void accept(String name, ArrayBuffer buffer);
|
||||
}
|
||||
|
||||
private static class FileChooserCallbackImpl implements FileChooserCallback {
|
||||
|
||||
private static final FileChooserCallbackImpl instance = new FileChooserCallbackImpl();
|
||||
|
||||
@Override
|
||||
public void accept(String name, ArrayBuffer buffer) {
|
||||
fileChooserHasResult = true;
|
||||
if(name == null) {
|
||||
fileChooserResultObject = null;
|
||||
}else {
|
||||
Int8Array typedArray = Int8Array.create(buffer);
|
||||
byte[] bytes = new byte[typedArray.getByteLength()];
|
||||
for(int i = 0; i < bytes.length; ++i) {
|
||||
bytes[i] = typedArray.get(i);
|
||||
}
|
||||
fileChooserResultObject = new FileChooserResult(name, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static volatile boolean fileChooserHasResult = false;
|
||||
private static volatile FileChooserResult fileChooserResultObject = null;
|
||||
|
||||
@JSBody(params = { "inputElement", "callback" }, script =
|
||||
"if(inputElement.files.length > 0) {"
|
||||
+ "const value = inputElement.files[0];"
|
||||
+ "value.arrayBuffer().then(function(arr){ callback(value.name, arr); })"
|
||||
+ ".catch(function(){ callback(null, null); });"
|
||||
+ "} else callback(null, null);")
|
||||
private static native void getFileChooserResult(HTMLInputElement inputElement, FileChooserCallback callback);
|
||||
|
||||
@JSBody(params = { "inputElement", "value" }, script = "inputElement.accept = value;")
|
||||
private static native void setAcceptSelection(HTMLInputElement inputElement, String value);
|
||||
|
||||
@JSBody(params = { "inputElement", "enable" }, script = "inputElement.multiple = enable;")
|
||||
private static native void setMultipleSelection(HTMLInputElement inputElement, boolean enable);
|
||||
|
||||
public static void displayFileChooser(String mime, String ext) {
|
||||
final HTMLInputElement inputElement = (HTMLInputElement) Window.current().getDocument().createElement("input");
|
||||
inputElement.setType("file");
|
||||
if(mime == null) {
|
||||
setAcceptSelection(inputElement, "." + ext);
|
||||
}else {
|
||||
setAcceptSelection(inputElement, mime);
|
||||
}
|
||||
setMultipleSelection(inputElement, false);
|
||||
inputElement.addEventListener("change", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
getFileChooserResult(inputElement, FileChooserCallbackImpl.instance);
|
||||
}
|
||||
});
|
||||
inputElement.click();
|
||||
}
|
||||
|
||||
public static boolean fileChooserHasResult() {
|
||||
return fileChooserHasResult;
|
||||
}
|
||||
|
||||
public static FileChooserResult getFileChooserResult() {
|
||||
fileChooserHasResult = false;
|
||||
FileChooserResult res = fileChooserResultObject;
|
||||
fileChooserResultObject = null;
|
||||
return res;
|
||||
}
|
||||
|
||||
@JSBody(params = { "doc", "str" }, script = "doc.write(str);")
|
||||
private static native void documentWrite(Document doc, String str);
|
||||
|
||||
public static void openCreditsPopup(String text) {
|
||||
Window currentWin = Window.current();
|
||||
|
||||
int w = (int)(530 * currentWin.getDevicePixelRatio());
|
||||
int h = (int)(450 * currentWin.getDevicePixelRatio());
|
||||
|
||||
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");
|
||||
|
||||
newWin.focus();
|
||||
documentWrite(newWin.getDocument(), "<html><head><title>EaglercraftX 1.8 Credits</title></head><body><pre>" + text + "</pre></body></html>");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.canvas.CanvasRenderingContext2D;
|
||||
import org.teavm.jso.dom.events.Event;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.dom.html.HTMLCanvasElement;
|
||||
import org.teavm.jso.dom.html.HTMLImageElement;
|
||||
import org.teavm.jso.dom.xml.Document;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.DataView;
|
||||
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.teavm.MainClass;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformAssets {
|
||||
|
||||
private static final byte[] MISSING_FILE = new byte[0];
|
||||
|
||||
static final Map<String,byte[]> assets = new HashMap();
|
||||
|
||||
public static final 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")) {
|
||||
ArrayBuffer file = PlatformRuntime.downloadRemoteURI(
|
||||
MainClass.configLocalesFolder + "/" + path.substring(22));
|
||||
if(file != null && file.getByteLength() > 0) {
|
||||
data = TeaVMUtils.arrayBufferToBytes(file);
|
||||
assets.put(path, data);
|
||||
return data;
|
||||
}else {
|
||||
assets.put(path, MISSING_FILE);
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
return data == MISSING_FILE ? null : data;
|
||||
}
|
||||
}
|
||||
|
||||
public static final ImageData loadImageFile(InputStream data) {
|
||||
byte[] b = EaglerInputStream.inputStreamToBytesQuiet(data);
|
||||
if(b != null) {
|
||||
return loadImageFile(b);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static HTMLCanvasElement imageLoadCanvas = null;
|
||||
private static CanvasRenderingContext2D imageLoadContext = null;
|
||||
|
||||
public static ImageData loadImageFile(byte[] data) {
|
||||
Uint8Array buf = Uint8Array.create(data.length);
|
||||
buf.set(data);
|
||||
return loadImageFile(buf.getBuffer());
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "return { willReadFrequently: true };")
|
||||
public static native JSObject youEagler();
|
||||
|
||||
@Async
|
||||
private static native ImageData loadImageFile(ArrayBuffer data);
|
||||
|
||||
private static void loadImageFile(ArrayBuffer data, final AsyncCallback<ImageData> ret) {
|
||||
final Document doc = Window.current().getDocument();
|
||||
final HTMLImageElement toLoad = (HTMLImageElement) doc.createElement("img");
|
||||
toLoad.addEventListener("load", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
if(imageLoadCanvas == null) {
|
||||
imageLoadCanvas = (HTMLCanvasElement) doc.createElement("canvas");
|
||||
}
|
||||
if(imageLoadCanvas.getWidth() < toLoad.getWidth()) {
|
||||
imageLoadCanvas.setWidth(toLoad.getWidth());
|
||||
}
|
||||
if(imageLoadCanvas.getHeight() < toLoad.getHeight()) {
|
||||
imageLoadCanvas.setHeight(toLoad.getHeight());
|
||||
}
|
||||
if(imageLoadContext == null) {
|
||||
imageLoadContext = (CanvasRenderingContext2D) imageLoadCanvas.getContext("2d", youEagler());
|
||||
}
|
||||
imageLoadContext.clearRect(0, 0, toLoad.getWidth(), toLoad.getHeight());
|
||||
imageLoadContext.drawImage(toLoad, 0, 0, toLoad.getWidth(), toLoad.getHeight());
|
||||
org.teavm.jso.canvas.ImageData pxlsDat = imageLoadContext.getImageData(0, 0, toLoad.getWidth(), toLoad.getHeight());
|
||||
Uint8ClampedArray pxls = pxlsDat.getData();
|
||||
int totalPixels = pxlsDat.getWidth() * pxlsDat.getHeight();
|
||||
TeaVMUtils.freeDataURL(toLoad.getSrc());
|
||||
if(pxls.getByteLength() < totalPixels << 2) {
|
||||
ret.complete(null);
|
||||
return;
|
||||
}
|
||||
DataView view = DataView.create(pxls.getBuffer());
|
||||
int[] pixels = new int[totalPixels];
|
||||
for(int i = 0; i < pixels.length; ++i) {
|
||||
pixels[i] = view.getUint32(i << 2, true);
|
||||
}
|
||||
ret.complete(new ImageData(pxlsDat.getWidth(), pxlsDat.getHeight(), pixels, true));
|
||||
}
|
||||
});
|
||||
toLoad.addEventListener("error", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
TeaVMUtils.freeDataURL(toLoad.getSrc());
|
||||
ret.complete(null);
|
||||
}
|
||||
});
|
||||
String src = TeaVMUtils.getDataURL(data, "image/png");
|
||||
if(src != null) {
|
||||
toLoad.setSrc(src);
|
||||
}else {
|
||||
ret.complete(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,337 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.SoundCategory;
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
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.DecodeErrorCallback;
|
||||
import org.teavm.jso.webaudio.DecodeSuccessCallback;
|
||||
import org.teavm.jso.webaudio.GainNode;
|
||||
import org.teavm.jso.webaudio.MediaEvent;
|
||||
import org.teavm.jso.webaudio.MediaStream;
|
||||
import org.teavm.jso.webaudio.MediaStreamAudioDestinationNode;
|
||||
import org.teavm.jso.webaudio.PannerNode;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformAudio {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("BrowserAudio");
|
||||
|
||||
private static AudioContext audioctx = null;
|
||||
private static MediaStreamAudioDestinationNode recDest = null;
|
||||
private static final Map<String, BrowserAudioResource> soundCache = new HashMap();
|
||||
|
||||
private static long cacheFreeTimer = 0l;
|
||||
|
||||
protected static class BrowserAudioResource implements IAudioResource {
|
||||
|
||||
protected AudioBuffer buffer;
|
||||
protected long cacheHit = 0l;
|
||||
|
||||
protected BrowserAudioResource(AudioBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class BrowserAudioHandle implements IAudioHandle, EventListener<MediaEvent> {
|
||||
|
||||
protected final BrowserAudioResource resource;
|
||||
protected AudioBufferSourceNode source;
|
||||
protected final PannerNode panner;
|
||||
protected final GainNode gain;
|
||||
protected float pitch;
|
||||
protected boolean isPaused = false;
|
||||
protected boolean isEnded = false;
|
||||
|
||||
public BrowserAudioHandle(BrowserAudioResource resource, AudioBufferSourceNode source, PannerNode panner,
|
||||
GainNode gain, float pitch) {
|
||||
this.resource = resource;
|
||||
this.source = source;
|
||||
this.panner = panner;
|
||||
this.gain = gain;
|
||||
this.pitch = pitch;
|
||||
source.setOnEnded(this);
|
||||
}
|
||||
|
||||
@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 restart() {
|
||||
if(isEnded) {
|
||||
isEnded = false;
|
||||
AudioBufferSourceNode src = audioctx.createBufferSource();
|
||||
resource.cacheHit = System.currentTimeMillis();
|
||||
src.setBuffer(resource.buffer);
|
||||
src.getPlaybackRate().setValue(pitch);
|
||||
source.disconnect();
|
||||
src.connect(panner == null ? gain : panner);
|
||||
source = src;
|
||||
source.start();
|
||||
}else {
|
||||
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) {
|
||||
isEnded = true;
|
||||
source.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFree() {
|
||||
return isEnded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(MediaEvent evt) {
|
||||
isEnded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void initialize() {
|
||||
|
||||
try {
|
||||
audioctx = AudioContext.create();
|
||||
recDest = audioctx.createMediaStreamDestination();
|
||||
}catch(Throwable t) {
|
||||
throw new PlatformRuntime.RuntimeInitializationFailureException("Could not initialize audio context!", t);
|
||||
}
|
||||
|
||||
PlatformInput.clearEvenBuffers();
|
||||
|
||||
}
|
||||
|
||||
private static GainNode micGain;
|
||||
|
||||
public static void setMicVol(float vol) {
|
||||
if (micGain == null) return;
|
||||
micGain.getGain().setValue(vol);
|
||||
}
|
||||
|
||||
protected static void initRecDest() {
|
||||
AudioBufferSourceNode absn = audioctx.createBufferSource();
|
||||
AudioBuffer ab = audioctx.createBuffer(1, 1, 48000);
|
||||
ab.copyToChannel(new float[] { 0 }, 0);
|
||||
absn.setBuffer(ab);
|
||||
absn.setLoop(true);
|
||||
absn.start();
|
||||
absn.connect(recDest);
|
||||
MediaStream mic = PlatformRuntime.getMic();
|
||||
if (mic != null) {
|
||||
micGain = audioctx.createGain();
|
||||
micGain.getGain().setValue(Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.VOICE));
|
||||
audioctx.createMediaStreamSource(mic).connect(micGain);
|
||||
micGain.connect(recDest);
|
||||
}
|
||||
}
|
||||
|
||||
protected static MediaStream getRecStream() {
|
||||
return recDest.getStream();
|
||||
}
|
||||
|
||||
public static IAudioResource loadAudioData(String filename, boolean holdInCache) {
|
||||
BrowserAudioResource buffer;
|
||||
synchronized(soundCache) {
|
||||
buffer = soundCache.get(filename);
|
||||
}
|
||||
if(buffer == null) {
|
||||
byte[] file = PlatformAssets.getResourceBytes(filename);
|
||||
if(file == null) return null;
|
||||
Uint8Array buf = Uint8Array.create(file.length);
|
||||
buf.set(file);
|
||||
buffer = new BrowserAudioResource(decodeAudioAsync(buf.getBuffer(), filename));
|
||||
if(holdInCache) {
|
||||
synchronized(soundCache) {
|
||||
soundCache.put(filename, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(buffer.buffer != null) {
|
||||
buffer.cacheHit = System.currentTimeMillis();
|
||||
return buffer;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
public static native AudioBuffer decodeAudioAsync(ArrayBuffer buffer, String errorFileName);
|
||||
|
||||
private static void decodeAudioAsync(ArrayBuffer buffer, final String errorFileName, final AsyncCallback<AudioBuffer> cb) {
|
||||
audioctx.decodeAudioData(buffer, new DecodeSuccessCallback() {
|
||||
@Override
|
||||
public void onSuccess(AudioBuffer decodedData) {
|
||||
cb.complete(decodedData);
|
||||
}
|
||||
}, new DecodeErrorCallback() {
|
||||
@Override
|
||||
public void onError(JSObject error) {
|
||||
logger.error("Could not load audio: {}", errorFileName);
|
||||
cb.complete(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void clearAudioCache() {
|
||||
long millis = System.currentTimeMillis();
|
||||
if(millis - cacheFreeTimer > 30000l) {
|
||||
cacheFreeTimer = millis;
|
||||
synchronized(soundCache) {
|
||||
Iterator<BrowserAudioResource> itr = soundCache.values().iterator();
|
||||
while(itr.hasNext()) {
|
||||
if(millis - itr.next().cacheHit > 600000l) { // 10 minutes
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean available() {
|
||||
return true; // this is not used
|
||||
}
|
||||
|
||||
public static IAudioHandle beginPlayback(IAudioResource track, float x, float y, float z,
|
||||
float volume, float pitch) {
|
||||
BrowserAudioResource internalTrack = (BrowserAudioResource) track;
|
||||
internalTrack.cacheHit = System.currentTimeMillis();
|
||||
|
||||
AudioBufferSourceNode src = audioctx.createBufferSource();
|
||||
src.setBuffer(internalTrack.buffer);
|
||||
src.getPlaybackRate().setValue(pitch);
|
||||
|
||||
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);
|
||||
panner.setDistanceModel("linear");
|
||||
panner.setPanningModel("HRTF");
|
||||
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());
|
||||
gain.connect(recDest);
|
||||
|
||||
src.start();
|
||||
|
||||
return new BrowserAudioHandle(internalTrack, src, panner, gain, pitch);
|
||||
}
|
||||
|
||||
public static IAudioHandle beginPlaybackStatic(IAudioResource track, float volume, float pitch) {
|
||||
BrowserAudioResource internalTrack = (BrowserAudioResource) track;
|
||||
internalTrack.cacheHit = System.currentTimeMillis();
|
||||
|
||||
AudioBufferSourceNode src = audioctx.createBufferSource();
|
||||
src.setBuffer(internalTrack.buffer);
|
||||
src.getPlaybackRate().setValue(pitch);
|
||||
|
||||
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());
|
||||
gain.connect(recDest);
|
||||
|
||||
src.start();
|
||||
|
||||
return new BrowserAudioHandle(internalTrack, src, null, gain, pitch);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformBufferFunctions {
|
||||
|
||||
public static void put(ByteBuffer newBuffer, ByteBuffer flip) {
|
||||
int len = flip.remaining();
|
||||
for(int i = 0; i < len; ++i) {
|
||||
newBuffer.put(flip.get());
|
||||
}
|
||||
}
|
||||
|
||||
public static void put(IntBuffer intBuffer, int index, int[] data) {
|
||||
int p = intBuffer.position();
|
||||
intBuffer.position(index);
|
||||
intBuffer.put(data);
|
||||
intBuffer.position(p);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,530 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.browser.TimerHandler;
|
||||
import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.dom.events.KeyboardEvent;
|
||||
import org.teavm.jso.dom.events.MouseEvent;
|
||||
import org.teavm.jso.dom.events.WheelEvent;
|
||||
import org.teavm.jso.dom.html.HTMLCanvasElement;
|
||||
import org.teavm.jso.webgl.WebGLFramebuffer;
|
||||
import org.teavm.jso.webgl.WebGLRenderbuffer;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EarlyLoadScreen;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContext;
|
||||
|
||||
import static net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContext.*;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformInput {
|
||||
|
||||
private static Window win = null;
|
||||
private static HTMLCanvasElement canvas = null;
|
||||
static WebGL2RenderingContext context = null;
|
||||
|
||||
static WebGLFramebuffer mainFramebuffer = null;
|
||||
static WebGLRenderbuffer mainColorRenderbuffer = null;
|
||||
static WebGLRenderbuffer mainDepthRenderbuffer = null;
|
||||
private static int framebufferWidth = -1;
|
||||
private static int framebufferHeight = -1;
|
||||
|
||||
private static EventListener contextmenu = null;
|
||||
private static EventListener mousedown = null;
|
||||
private static EventListener mouseup = null;
|
||||
private static EventListener mousemove = null;
|
||||
private static EventListener mouseenter = null;
|
||||
private static EventListener mouseleave = null;
|
||||
private static EventListener keydown = null;
|
||||
private static EventListener keyup = null;
|
||||
private static EventListener keypress = null;
|
||||
private static EventListener wheel = null;
|
||||
private static EventListener pointerlock = null;
|
||||
|
||||
private static List<MouseEvent> mouseEvents = new LinkedList();
|
||||
private static List<KeyboardEvent> keyEvents = new LinkedList();
|
||||
|
||||
private static int mouseX = 0;
|
||||
private static int mouseY = 0;
|
||||
private static double mouseDX = 0.0D;
|
||||
private static double mouseDY = 0.0D;
|
||||
private static double mouseDWheel = 0.0D;
|
||||
private static int width = 0;
|
||||
private static int height = 0;
|
||||
private static boolean enableRepeatEvents = true;
|
||||
private static boolean isWindowFocused = true;
|
||||
private static boolean isMouseOverWindow = true;
|
||||
static boolean unpressCTRL = false;
|
||||
|
||||
private static int windowWidth = -1;
|
||||
private static int windowHeight = -1;
|
||||
private static int lastWasResizedWindowWidth = -2;
|
||||
private static int lastWasResizedWindowHeight = -2;
|
||||
|
||||
private static MouseEvent currentEvent = null;
|
||||
private static KeyboardEvent currentEventK = null;
|
||||
private static boolean[] buttonStates = new boolean[8];
|
||||
private static boolean[] keyStates = new boolean[256];
|
||||
|
||||
private static int functionKeyModifier = KeyboardConstants.KEY_F;
|
||||
|
||||
private static long mouseUngrabTimer = 0l;
|
||||
private static long mouseGrabTimer = 0l;
|
||||
private static int mouseUngrabTimeout = -1;
|
||||
private static boolean pointerLockFlag = false;
|
||||
|
||||
@JSBody(params = { }, script = "window.onbeforeunload = () => {return false;};")
|
||||
private static native void onBeforeCloseRegister();
|
||||
|
||||
static void initHooks(Window window, HTMLCanvasElement canvaz) {
|
||||
win = window;
|
||||
canvas = canvaz;
|
||||
|
||||
win.addEventListener("contextmenu", contextmenu = new EventListener<MouseEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MouseEvent evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
}
|
||||
});
|
||||
canvas.addEventListener("mousedown", mousedown = new EventListener<MouseEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MouseEvent evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
int b = evt.getButton();
|
||||
buttonStates[b == 1 ? 2 : (b == 2 ? 1 : b)] = true;
|
||||
mouseEvents.add(evt);
|
||||
}
|
||||
});
|
||||
canvas.addEventListener("mouseup", mouseup = new EventListener<MouseEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MouseEvent evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
int b = evt.getButton();
|
||||
buttonStates[b == 1 ? 2 : (b == 2 ? 1 : b)] = false;
|
||||
mouseEvents.add(evt);
|
||||
}
|
||||
});
|
||||
canvas.addEventListener("mousemove", mousemove = new EventListener<MouseEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MouseEvent evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
mouseX = (int)(getOffsetX(evt) * win.getDevicePixelRatio());
|
||||
mouseY = (int)((canvas.getClientHeight() - getOffsetY(evt)) * win.getDevicePixelRatio());
|
||||
mouseDX += evt.getMovementX();
|
||||
mouseDY += -evt.getMovementY();
|
||||
if(hasBeenActive()) {
|
||||
mouseEvents.add(evt);
|
||||
}
|
||||
}
|
||||
});
|
||||
canvas.addEventListener("mouseenter", mouseenter = new EventListener<MouseEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MouseEvent evt) {
|
||||
isMouseOverWindow = true;
|
||||
}
|
||||
});
|
||||
canvas.addEventListener("mouseleave", mouseleave = new EventListener<MouseEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MouseEvent evt) {
|
||||
isMouseOverWindow = false;
|
||||
}
|
||||
});
|
||||
win.addEventListener("keydown", keydown = new EventListener<KeyboardEvent>() {
|
||||
@Override
|
||||
public void handleEvent(KeyboardEvent evt) {
|
||||
int w = getWhich(evt);
|
||||
if (w == 122) return; // F11
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if(!enableRepeatEvents && evt.isRepeat()) return;
|
||||
w = processFunctionKeys(w);
|
||||
keyStates[KeyboardConstants.getEaglerKeyFromBrowser(w, evt.getLocation())] = true;
|
||||
keyEvents.add(evt);
|
||||
}
|
||||
});
|
||||
win.addEventListener("keyup", keyup = new EventListener<KeyboardEvent>() {
|
||||
@Override
|
||||
public void handleEvent(KeyboardEvent evt) {
|
||||
int w = getWhich(evt);
|
||||
if (w == 122) return; // F11
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if(!enableRepeatEvents && evt.isRepeat()) return;
|
||||
w = processFunctionKeys(w);
|
||||
keyStates[KeyboardConstants.getEaglerKeyFromBrowser(w, evt.getLocation())] = false;
|
||||
keyEvents.add(evt);
|
||||
}
|
||||
});
|
||||
win.addEventListener("keypress", keypress = new EventListener<KeyboardEvent>() {
|
||||
@Override
|
||||
public void handleEvent(KeyboardEvent evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if(enableRepeatEvents && evt.isRepeat()) keyEvents.add(evt);
|
||||
}
|
||||
});
|
||||
canvas.addEventListener("wheel", wheel = new EventListener<WheelEvent>() {
|
||||
@Override
|
||||
public void handleEvent(WheelEvent evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
mouseEvents.add(evt);
|
||||
mouseDWheel += evt.getDeltaY();
|
||||
}
|
||||
});
|
||||
win.addEventListener("blur", new EventListener<WheelEvent>() {
|
||||
@Override
|
||||
public void handleEvent(WheelEvent evt) {
|
||||
isWindowFocused = false;
|
||||
for(int i = 0; i < buttonStates.length; ++i) {
|
||||
buttonStates[i] = false;
|
||||
}
|
||||
for(int i = 0; i < keyStates.length; ++i) {
|
||||
keyStates[i] = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
win.addEventListener("focus", new EventListener<WheelEvent>() {
|
||||
@Override
|
||||
public void handleEvent(WheelEvent evt) {
|
||||
isWindowFocused = true;
|
||||
}
|
||||
});
|
||||
win.getDocument().addEventListener("pointerlockchange", pointerlock = new EventListener<WheelEvent>() {
|
||||
@Override
|
||||
public void handleEvent(WheelEvent evt) {
|
||||
Window.setTimeout(new TimerHandler() {
|
||||
@Override
|
||||
public void onTimer() {
|
||||
boolean grab = isPointerLocked();
|
||||
if(!grab) {
|
||||
if(pointerLockFlag) {
|
||||
mouseUngrabTimer = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
pointerLockFlag = grab;
|
||||
}
|
||||
}, 60);
|
||||
mouseDX = 0.0D;
|
||||
mouseDY = 0.0D;
|
||||
}
|
||||
});
|
||||
onBeforeCloseRegister();
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "if(window.navigator.userActivation){return window.navigator.userActivation.hasBeenActive;}else{return false;}")
|
||||
public static native boolean hasBeenActive();
|
||||
|
||||
@JSBody(params = { "m" }, script = "return m.offsetX;")
|
||||
private static native int getOffsetX(MouseEvent m);
|
||||
|
||||
@JSBody(params = { "m" }, script = "return m.offsetY;")
|
||||
private static native int getOffsetY(MouseEvent m);
|
||||
|
||||
@JSBody(params = { "e" }, script = "return e.which;")
|
||||
private static native int getWhich(KeyboardEvent e);
|
||||
|
||||
public static int getWindowWidth() {
|
||||
return windowWidth;
|
||||
}
|
||||
|
||||
public static int getWindowHeight() {
|
||||
return windowHeight;
|
||||
}
|
||||
|
||||
public static boolean getWindowFocused() {
|
||||
return isWindowFocused || isPointerLocked();
|
||||
}
|
||||
|
||||
public static boolean isCloseRequested() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void update() {
|
||||
double r = win.getDevicePixelRatio();
|
||||
int w = PlatformRuntime.parent.getClientWidth();
|
||||
int h = PlatformRuntime.parent.getClientHeight();
|
||||
int w2 = windowWidth = (int)(w * r);
|
||||
int h2 = windowHeight = (int)(h * r);
|
||||
if(canvas.getWidth() != w2) {
|
||||
canvas.setWidth(w2);
|
||||
}
|
||||
if(canvas.getHeight() != h2) {
|
||||
canvas.setHeight(h2);
|
||||
}
|
||||
flipBuffer();
|
||||
EagUtils.sleep(1l);
|
||||
}
|
||||
|
||||
static void initFramebuffer(WebGL2RenderingContext ctx, WebGLFramebuffer fbo, int sw, int sh) {
|
||||
context = ctx;
|
||||
mainFramebuffer = fbo;
|
||||
|
||||
framebufferWidth = windowWidth = sw;
|
||||
framebufferHeight = windowHeight = sh;
|
||||
|
||||
ctx.bindFramebuffer(FRAMEBUFFER, fbo);
|
||||
|
||||
mainColorRenderbuffer = ctx.createRenderbuffer();
|
||||
mainDepthRenderbuffer = ctx.createRenderbuffer();
|
||||
|
||||
ctx.bindRenderbuffer(RENDERBUFFER, mainColorRenderbuffer);
|
||||
ctx.renderbufferStorage(RENDERBUFFER, RGBA8, sw, sh);
|
||||
ctx.framebufferRenderbuffer(FRAMEBUFFER, COLOR_ATTACHMENT0, RENDERBUFFER, mainColorRenderbuffer);
|
||||
|
||||
ctx.bindRenderbuffer(RENDERBUFFER, mainDepthRenderbuffer);
|
||||
ctx.renderbufferStorage(RENDERBUFFER, DEPTH_COMPONENT32F, sw, sh);
|
||||
ctx.framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, mainDepthRenderbuffer);
|
||||
|
||||
ctx.drawBuffers(new int[] { COLOR_ATTACHMENT0 });
|
||||
}
|
||||
|
||||
private static void flipBuffer() {
|
||||
|
||||
context.bindFramebuffer(READ_FRAMEBUFFER, mainFramebuffer);
|
||||
context.bindFramebuffer(DRAW_FRAMEBUFFER, null);
|
||||
context.blitFramebuffer(0, 0, framebufferWidth, framebufferHeight, 0, 0, windowWidth, windowHeight, COLOR_BUFFER_BIT, NEAREST);
|
||||
|
||||
context.bindFramebuffer(FRAMEBUFFER, mainFramebuffer);
|
||||
|
||||
if(windowWidth != framebufferWidth || windowHeight != framebufferHeight) {
|
||||
framebufferWidth = windowWidth;
|
||||
framebufferHeight = windowHeight;
|
||||
|
||||
context.bindRenderbuffer(RENDERBUFFER, mainColorRenderbuffer);
|
||||
context.renderbufferStorage(RENDERBUFFER, RGBA8, framebufferWidth, framebufferHeight);
|
||||
|
||||
context.bindRenderbuffer(RENDERBUFFER, mainDepthRenderbuffer);
|
||||
context.renderbufferStorage(RENDERBUFFER, DEPTH_COMPONENT32F, framebufferWidth, framebufferHeight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean wasResized() {
|
||||
if(windowWidth != lastWasResizedWindowWidth || windowHeight != lastWasResizedWindowHeight) {
|
||||
lastWasResizedWindowWidth = windowWidth;
|
||||
lastWasResizedWindowHeight = windowHeight;
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean keyboardNext() {
|
||||
if(unpressCTRL) { //un-press ctrl after copy/paste permission
|
||||
keyEvents.clear();
|
||||
currentEventK = null;
|
||||
keyStates[29] = false;
|
||||
keyStates[157] = false;
|
||||
keyStates[28] = false;
|
||||
keyStates[219] = false;
|
||||
keyStates[220] = false;
|
||||
unpressCTRL = false;
|
||||
return false;
|
||||
}
|
||||
currentEventK = null;
|
||||
return !keyEvents.isEmpty() && (currentEventK = keyEvents.remove(0)) != null;
|
||||
}
|
||||
|
||||
public static boolean keyboardGetEventKeyState() {
|
||||
return currentEventK == null? false : !currentEventK.getType().equals("keyup");
|
||||
}
|
||||
|
||||
public static int keyboardGetEventKey() {
|
||||
int w = processFunctionKeys(getWhich(currentEventK));
|
||||
return currentEventK == null ? -1 : KeyboardConstants.getEaglerKeyFromBrowser(w, currentEventK.getLocation());
|
||||
}
|
||||
|
||||
public static char keyboardGetEventCharacter() {
|
||||
if(currentEventK == null) return '\0';
|
||||
String s = currentEventK.getKey();
|
||||
return currentEventK == null ? ' ' : (char) (s.length() > 1 ? '\0' : s.charAt(0));
|
||||
}
|
||||
|
||||
public static boolean keyboardIsKeyDown(int key) {
|
||||
if(unpressCTRL) { //un-press ctrl after copy/paste permission
|
||||
keyStates[28] = false;
|
||||
keyStates[29] = false;
|
||||
keyStates[157] = false;
|
||||
keyStates[219] = false;
|
||||
keyStates[220] = false;
|
||||
}
|
||||
return key < 0 || key >= keyStates.length ? false : keyStates[key];
|
||||
}
|
||||
|
||||
public static boolean keyboardIsRepeatEvent() {
|
||||
return currentEventK == null ? false : currentEventK.isRepeat();
|
||||
}
|
||||
|
||||
public static void keyboardEnableRepeatEvents(boolean b) {
|
||||
enableRepeatEvents = b;
|
||||
}
|
||||
|
||||
public static boolean mouseNext() {
|
||||
currentEvent = null;
|
||||
return !mouseEvents.isEmpty() && (currentEvent = mouseEvents.remove(0)) != null;
|
||||
}
|
||||
|
||||
public static boolean mouseGetEventButtonState() {
|
||||
return currentEvent == null ? false : currentEvent.getType().equals(MouseEvent.MOUSEDOWN);
|
||||
}
|
||||
|
||||
public static int mouseGetEventButton() {
|
||||
if(currentEvent == null || currentEvent.getType().equals(MouseEvent.MOUSEMOVE)) return -1;
|
||||
int b = currentEvent.getButton();
|
||||
return b == 1 ? 2 : (b == 2 ? 1 : b);
|
||||
}
|
||||
|
||||
public static int mouseGetEventX() {
|
||||
return currentEvent == null ? -1 : (int)(currentEvent.getClientX() * win.getDevicePixelRatio());
|
||||
}
|
||||
|
||||
public static int mouseGetEventY() {
|
||||
return currentEvent == null ? -1 : (int)((canvas.getClientHeight() - currentEvent.getClientY()) * win.getDevicePixelRatio());
|
||||
}
|
||||
|
||||
public static int mouseGetEventDWheel() {
|
||||
return ("wheel".equals(currentEvent.getType())) ? (((WheelEvent)currentEvent).getDeltaY() == 0.0D ? 0 : (((WheelEvent)currentEvent).getDeltaY() > 0.0D ? -1 : 1)) : 0;
|
||||
}
|
||||
|
||||
public static int mouseGetX() {
|
||||
return mouseX;
|
||||
}
|
||||
|
||||
public static int mouseGetY() {
|
||||
return mouseY;
|
||||
}
|
||||
|
||||
public static boolean mouseIsButtonDown(int i) {
|
||||
return buttonStates[i];
|
||||
}
|
||||
|
||||
public static int mouseGetDWheel() {
|
||||
int ret = (int)mouseDWheel;
|
||||
mouseDWheel = 0.0D;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void mouseSetGrabbed(boolean grab) {
|
||||
long t = System.currentTimeMillis();
|
||||
pointerLockFlag = grab;
|
||||
mouseGrabTimer = t;
|
||||
if(grab) {
|
||||
canvas.requestPointerLock();
|
||||
if(mouseUngrabTimeout != -1) Window.clearTimeout(mouseUngrabTimeout);
|
||||
mouseUngrabTimeout = -1;
|
||||
if(t - mouseUngrabTimer < 3000l) {
|
||||
mouseUngrabTimeout = Window.setTimeout(new TimerHandler() {
|
||||
@Override
|
||||
public void onTimer() {
|
||||
canvas.requestPointerLock();
|
||||
}
|
||||
}, 3100 - (int)(t - mouseUngrabTimer));
|
||||
}
|
||||
}else {
|
||||
if(mouseUngrabTimeout != -1) Window.clearTimeout(mouseUngrabTimeout);
|
||||
mouseUngrabTimeout = -1;
|
||||
Window.current().getDocument().exitPointerLock();
|
||||
}
|
||||
mouseDX = 0.0D;
|
||||
mouseDY = 0.0D;
|
||||
}
|
||||
|
||||
public static boolean isMouseGrabbed() {
|
||||
return pointerLockFlag;
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "return document.pointerLockElement != null;")
|
||||
public static native boolean isPointerLocked();
|
||||
|
||||
public static int mouseGetDX() {
|
||||
int ret = (int)mouseDX;
|
||||
mouseDX = 0.0D;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int mouseGetDY() {
|
||||
int ret = (int)mouseDY;
|
||||
mouseDY = 0.0D;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void mouseSetCursorPosition(int x, int y) {
|
||||
// obsolete
|
||||
}
|
||||
|
||||
public static boolean mouseIsInsideWindow() {
|
||||
return isMouseOverWindow;
|
||||
}
|
||||
|
||||
public static boolean contextLost() {
|
||||
return PlatformRuntime.webgl.isContextLost();
|
||||
}
|
||||
|
||||
private static int processFunctionKeys(int key) {
|
||||
if(keyboardIsKeyDown(functionKeyModifier)) {
|
||||
if(key >= 49 && key <= 57) {
|
||||
key = key - 49 + 112;
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public static void setFunctionKeyModifier(int key) {
|
||||
functionKeyModifier = key;
|
||||
}
|
||||
|
||||
public static void removeEventHandlers() {
|
||||
win.removeEventListener("contextmenu", contextmenu);
|
||||
canvas.removeEventListener("mousedown", mousedown);
|
||||
canvas.removeEventListener("mouseup", mouseup);
|
||||
canvas.removeEventListener("mousemove", mousemove);
|
||||
canvas.removeEventListener("mouseenter", mouseenter);
|
||||
canvas.removeEventListener("mouseleave", mouseleave);
|
||||
win.removeEventListener("keydown", keydown);
|
||||
win.removeEventListener("keyup", keyup);
|
||||
win.removeEventListener("keypress", keypress);
|
||||
canvas.removeEventListener("wheel", wheel);
|
||||
win.getDocument().removeEventListener("pointerlockchange", pointerlock);
|
||||
if(mouseUngrabTimeout != -1) {
|
||||
Window.clearTimeout(mouseUngrabTimeout);
|
||||
mouseUngrabTimeout = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void pressAnyKeyScreen() {
|
||||
if(mouseEvents.isEmpty() && keyEvents.isEmpty() && !hasBeenActive()) {
|
||||
EarlyLoadScreen.paintEnable();
|
||||
|
||||
while(mouseEvents.isEmpty() && keyEvents.isEmpty()) {
|
||||
EagUtils.sleep(100l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearEvenBuffers() {
|
||||
mouseEvents.clear();
|
||||
keyEvents.clear();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.dom.events.Event;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.dom.events.MessageEvent;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
import org.teavm.jso.websocket.WebSocket;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMServerQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformNetworking {
|
||||
|
||||
private static WebSocket sock = null;
|
||||
private static boolean sockIsConnecting = false;
|
||||
private static boolean sockIsConnected = false;
|
||||
private static boolean sockIsAlive = false;
|
||||
private static boolean sockIsFailed = false;
|
||||
private static LinkedList<byte[]> readPackets = new LinkedList();
|
||||
private static String currentSockURI = null;
|
||||
private static EnumServerRateLimit serverRateLimit = null;
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformNetworking");
|
||||
|
||||
public static EnumEaglerConnectionState playConnectionState() {
|
||||
return !sockIsConnected ? (sockIsFailed ? EnumEaglerConnectionState.FAILED : EnumEaglerConnectionState.CLOSED)
|
||||
: (sockIsConnecting ? EnumEaglerConnectionState.CONNECTING : EnumEaglerConnectionState.CONNECTED);
|
||||
}
|
||||
|
||||
public static void startPlayConnection(String destination) {
|
||||
sockIsFailed = !connectWebSocket(destination).booleanValue();
|
||||
}
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return typeof obj === \"string\";")
|
||||
private static native boolean isString(JSObject obj);
|
||||
|
||||
@Async
|
||||
public static native Boolean connectWebSocket(String sockURI);
|
||||
|
||||
private static void connectWebSocket(String sockURI, final AsyncCallback<Boolean> cb) {
|
||||
sockIsConnecting = true;
|
||||
sockIsConnected = false;
|
||||
sockIsAlive = false;
|
||||
currentSockURI = sockURI;
|
||||
try {
|
||||
sock = WebSocket.create(sockURI);
|
||||
} catch(Throwable t) {
|
||||
sockIsFailed = true;
|
||||
sockIsConnecting = false;
|
||||
sockIsAlive = false;
|
||||
cb.complete(Boolean.FALSE);
|
||||
return;
|
||||
}
|
||||
final WebSocket oldSock = sock;
|
||||
sock.setBinaryType("arraybuffer");
|
||||
TeaVMUtils.addEventListener(sock, "open", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
if (oldSock != sock) return;
|
||||
sockIsConnecting = false;
|
||||
sockIsAlive = false;
|
||||
sockIsConnected = true;
|
||||
synchronized(readPackets) {
|
||||
readPackets.clear();
|
||||
}
|
||||
cb.complete(Boolean.TRUE);
|
||||
}
|
||||
});
|
||||
TeaVMUtils.addEventListener(sock, "close", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
if (oldSock != sock) return;
|
||||
sock = null;
|
||||
boolean b = sockIsConnecting;
|
||||
sockIsConnecting = false;
|
||||
sockIsConnected = false;
|
||||
sockIsAlive = false;
|
||||
if(b) cb.complete(Boolean.FALSE);
|
||||
}
|
||||
});
|
||||
TeaVMUtils.addEventListener(sock, "message", new EventListener<MessageEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MessageEvent evt) {
|
||||
if (oldSock != sock) return;
|
||||
sockIsAlive = true;
|
||||
if(isString(evt.getData())) {
|
||||
String str = evt.getDataAsString();
|
||||
if(str.equalsIgnoreCase("BLOCKED")) {
|
||||
logger.error("Reached full IP ratelimit!");
|
||||
serverRateLimit = EnumServerRateLimit.BLOCKED;
|
||||
}else if(str.equalsIgnoreCase("LOCKED")) {
|
||||
logger.error("Reached full IP ratelimit lockout!");
|
||||
serverRateLimit = EnumServerRateLimit.LOCKED_OUT;
|
||||
}
|
||||
}else {
|
||||
Uint8Array a = Uint8Array.create(evt.getDataAsArray());
|
||||
byte[] b = new byte[a.getByteLength()];
|
||||
for(int i = 0; i < b.length; ++i) {
|
||||
b[i] = (byte) a.get(i);
|
||||
}
|
||||
synchronized(readPackets) {
|
||||
readPackets.add(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
TeaVMUtils.addEventListener(sock, "error", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
if (oldSock != sock) return;
|
||||
if(sockIsConnecting) {
|
||||
sockIsFailed = true;
|
||||
sockIsConnecting = false;
|
||||
sockIsAlive = false;
|
||||
cb.complete(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void playDisconnect() {
|
||||
if(sock != null) sock.close();
|
||||
sockIsConnecting = false;
|
||||
}
|
||||
|
||||
public static byte[] readPlayPacket() {
|
||||
synchronized(readPackets) {
|
||||
if(!readPackets.isEmpty()) {
|
||||
return readPackets.remove(0);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int countAvailableReadData() {
|
||||
int total = 0;
|
||||
synchronized(readPackets) {
|
||||
for(int i = 0, l = readPackets.size(); i < l; ++i) {
|
||||
total += readPackets.get(i).length;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);")
|
||||
private static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer);
|
||||
|
||||
public static void writePlayPacket(byte[] pkt) {
|
||||
if(sock != null && !sockIsConnecting) {
|
||||
Uint8Array arr = Uint8Array.create(pkt.length);
|
||||
arr.set(pkt);
|
||||
nativeBinarySend(sock, arr.getBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
public static IServerQuery sendServerQuery(String uri, String accept) {
|
||||
try {
|
||||
return new TeaVMServerQuery(uri, accept);
|
||||
}catch(Throwable t) {
|
||||
logger.error("Could not send query to \"{}\"!", uri);
|
||||
logger.error(t);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static EnumServerRateLimit getRateLimit() {
|
||||
return serverRateLimit == null ? EnumServerRateLimit.OK : serverRateLimit;
|
||||
}
|
||||
|
||||
public static String getCurrentURI() {
|
||||
return currentSockURI;
|
||||
}
|
||||
}
|
@ -0,0 +1,474 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
|
||||
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.teavm.WebGL2RenderingContext;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformOpenGL {
|
||||
|
||||
static WebGL2RenderingContext ctx = null;
|
||||
|
||||
static boolean hasDebugRenderInfoExt = false;
|
||||
|
||||
static void setCurrentContext(WebGL2RenderingContext context) {
|
||||
ctx = context;
|
||||
hasDebugRenderInfoExt = ctx.getExtension("WEBGL_debug_renderer_info") != null;
|
||||
_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
public static final void _wglEnable(int glEnum) {
|
||||
ctx.enable(glEnum);
|
||||
}
|
||||
|
||||
public static final void _wglDisable(int glEnum) {
|
||||
ctx.disable(glEnum);
|
||||
}
|
||||
|
||||
public static final void _wglClearColor(float r, float g, float b, float a) {
|
||||
ctx.clearColor(r, g, b, a);
|
||||
}
|
||||
|
||||
public static final void _wglClearDepth(float f) {
|
||||
ctx.clearDepth(f);
|
||||
}
|
||||
|
||||
public static final void _wglClear(int bits) {
|
||||
ctx.clear(bits);
|
||||
}
|
||||
|
||||
public static final void _wglDepthFunc(int glEnum) {
|
||||
ctx.depthFunc(glEnum);
|
||||
}
|
||||
|
||||
public static final void _wglDepthMask(boolean mask) {
|
||||
ctx.depthMask(mask);
|
||||
}
|
||||
|
||||
public static final void _wglCullFace(int glEnum) {
|
||||
ctx.cullFace(glEnum);
|
||||
}
|
||||
|
||||
public static final void _wglViewport(int x, int y, int w, int h) {
|
||||
ctx.viewport(x, y, w, h);
|
||||
}
|
||||
|
||||
public static final void _wglBlendFunc(int src, int dst) {
|
||||
ctx.blendFunc(src, dst);
|
||||
}
|
||||
|
||||
public static final void _wglBlendFuncSeparate(int srcColor, int dstColor,
|
||||
int srcAlpha, int dstAlpha) {
|
||||
ctx.blendFuncSeparate(srcColor, dstColor, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
public static final void _wglBlendEquation(int glEnum) {
|
||||
ctx.blendEquation(glEnum);
|
||||
}
|
||||
|
||||
public static final void _wglColorMask(boolean r, boolean g, boolean b, boolean a) {
|
||||
ctx.colorMask(r, g, b, a);
|
||||
}
|
||||
|
||||
public static final void _wglDrawBuffers(int buffer) {
|
||||
ctx.drawBuffers(new int[] { buffer });
|
||||
}
|
||||
|
||||
public static final void _wglDrawBuffers(int[] buffers) {
|
||||
ctx.drawBuffers(buffers);
|
||||
}
|
||||
|
||||
public static final void _wglReadBuffer(int buffer) {
|
||||
ctx.readBuffer(buffer);
|
||||
}
|
||||
|
||||
public static final void _wglPolygonOffset(float f1, float f2) {
|
||||
ctx.polygonOffset(f1, f2);
|
||||
}
|
||||
|
||||
public static final void _wglLineWidth(float width) {
|
||||
ctx.lineWidth(width);
|
||||
}
|
||||
|
||||
public static final IBufferGL _wglGenBuffers() {
|
||||
return new OpenGLObjects.BufferGL(ctx.createBuffer());
|
||||
}
|
||||
|
||||
public static final ITextureGL _wglGenTextures() {
|
||||
return new OpenGLObjects.TextureGL(ctx.createTexture());
|
||||
}
|
||||
|
||||
public static final IBufferArrayGL _wglGenVertexArrays() {
|
||||
return new OpenGLObjects.BufferArrayGL(ctx.createVertexArray());
|
||||
}
|
||||
|
||||
public static final IProgramGL _wglCreateProgram() {
|
||||
return new OpenGLObjects.ProgramGL(ctx.createProgram());
|
||||
}
|
||||
|
||||
public static final IShaderGL _wglCreateShader(int type) {
|
||||
return new OpenGLObjects.ShaderGL(ctx.createShader(type));
|
||||
}
|
||||
|
||||
public static final IFramebufferGL _wglCreateFramebuffer() {
|
||||
return new OpenGLObjects.FramebufferGL(ctx.createFramebuffer());
|
||||
}
|
||||
|
||||
public static final IRenderbufferGL _wglCreateRenderbuffer() {
|
||||
return new OpenGLObjects.RenderbufferGL(ctx.createRenderbuffer());
|
||||
}
|
||||
|
||||
public static final IQueryGL _wglGenQueries() {
|
||||
return new OpenGLObjects.QueryGL(ctx.createQuery());
|
||||
}
|
||||
|
||||
public static final void _wglDeleteBuffers(IBufferGL obj) {
|
||||
ctx.deleteBuffer(obj == null ? null : ((OpenGLObjects.BufferGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDeleteTextures(ITextureGL obj) {
|
||||
ctx.deleteTexture(obj == null ? null : ((OpenGLObjects.TextureGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDeleteVertexArrays(IBufferArrayGL obj) {
|
||||
ctx.deleteVertexArray(obj == null ? null : ((OpenGLObjects.BufferArrayGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDeleteProgram(IProgramGL obj) {
|
||||
ctx.deleteProgram(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDeleteShader(IShaderGL obj) {
|
||||
ctx.deleteShader(obj == null ? null : ((OpenGLObjects.ShaderGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDeleteFramebuffer(IFramebufferGL obj) {
|
||||
ctx.deleteFramebuffer(obj == null ? null : ((OpenGLObjects.FramebufferGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDeleteRenderbuffer(IRenderbufferGL obj) {
|
||||
ctx.deleteRenderbuffer(obj == null ? null : ((OpenGLObjects.RenderbufferGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDeleteQueries(IQueryGL obj) {
|
||||
ctx.deleteQuery(obj == null ? null : ((OpenGLObjects.QueryGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglBindBuffer(int target, IBufferGL obj) {
|
||||
ctx.bindBuffer(target, obj == null ? null : ((OpenGLObjects.BufferGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglBufferData(int target, ByteBuffer data, int usage) {
|
||||
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView(data), usage);
|
||||
}
|
||||
|
||||
public static final void _wglBufferData(int target, IntBuffer data, int usage) {
|
||||
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView(data), usage);
|
||||
}
|
||||
|
||||
public static final void _wglBufferData(int target, FloatBuffer data, int usage) {
|
||||
ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView(data), usage);
|
||||
}
|
||||
|
||||
public static final void _wglBufferData(int target, int size, int usage) {
|
||||
ctx.bufferData(target, size, usage);
|
||||
}
|
||||
|
||||
public static final void _wglBufferSubData(int target, int offset, ByteBuffer data) {
|
||||
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView(data));
|
||||
}
|
||||
|
||||
public static final void _wglBufferSubData(int target, int offset, IntBuffer data) {
|
||||
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView(data));
|
||||
}
|
||||
|
||||
public static final void _wglBufferSubData(int target, int offset, FloatBuffer data) {
|
||||
ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView(data));
|
||||
}
|
||||
|
||||
public static final void _wglBindVertexArray(IBufferArrayGL obj) {
|
||||
ctx.bindVertexArray(obj == null ? null : ((OpenGLObjects.BufferArrayGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglEnableVertexAttribArray(int index) {
|
||||
ctx.enableVertexAttribArray(index);
|
||||
}
|
||||
|
||||
public static final void _wglDisableVertexAttribArray(int index) {
|
||||
ctx.disableVertexAttribArray(index);
|
||||
}
|
||||
|
||||
public static final void _wglVertexAttribPointer(int index, int size, int type,
|
||||
boolean normalized, int stride, int offset) {
|
||||
ctx.vertexAttribPointer(index, size, type, normalized, stride, offset);
|
||||
}
|
||||
|
||||
public static final void _wglVertexAttribDivisor(int index, int divisor) {
|
||||
ctx.vertexAttribDivisor(index, divisor);
|
||||
}
|
||||
|
||||
public static final void _wglActiveTexture(int texture) {
|
||||
ctx.activeTexture(texture);
|
||||
}
|
||||
|
||||
public static final void _wglBindTexture(int target, ITextureGL obj) {
|
||||
ctx.bindTexture(target, obj == null ? null : ((OpenGLObjects.TextureGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglTexParameterf(int target, int param, float value) {
|
||||
ctx.texParameterf(target, param, value);
|
||||
}
|
||||
|
||||
public static final void _wglTexParameteri(int target, int param, int value) {
|
||||
ctx.texParameteri(target, param, value);
|
||||
}
|
||||
|
||||
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width,
|
||||
int height, int border, int format, int type, ByteBuffer data) {
|
||||
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
|
||||
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
|
||||
}
|
||||
|
||||
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width,
|
||||
int height, int border, int format, int type, IntBuffer data) {
|
||||
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
|
||||
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
|
||||
}
|
||||
|
||||
public static final void _wglTexImage2D(int target, int level, int internalFormat, int width,
|
||||
int height, int border, int format, int type, FloatBuffer data) {
|
||||
ctx.texImage2D(target, level, internalFormat, width, height, border, format, type,
|
||||
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
|
||||
}
|
||||
|
||||
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
|
||||
int width, int height, int format, int type, ByteBuffer data) {
|
||||
ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
|
||||
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
|
||||
}
|
||||
|
||||
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
|
||||
int width, int height, int format, int type, IntBuffer data) {
|
||||
ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
|
||||
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
|
||||
}
|
||||
|
||||
public static final void _wglTexSubImage2D(int target, int level, int xoffset, int yoffset,
|
||||
int width, int height, int format, int type, FloatBuffer data) {
|
||||
ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
|
||||
data == null ? null : EaglerArrayBufferAllocator.getDataViewStupid(data));
|
||||
}
|
||||
|
||||
public static final void _wglCopyTexSubImage2D(int target, int level, int xoffset, int yoffset,
|
||||
int x, int y, int width, int height) {
|
||||
ctx.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
||||
}
|
||||
|
||||
public static final void _wglPixelStorei(int pname, int value) {
|
||||
ctx.pixelStorei(pname, value);
|
||||
}
|
||||
|
||||
public static final void _wglGenerateMipmap(int target) {
|
||||
ctx.generateMipmap(target);
|
||||
}
|
||||
|
||||
public static final void _wglShaderSource(IShaderGL obj, String source) {
|
||||
ctx.shaderSource(obj == null ? null : ((OpenGLObjects.ShaderGL)obj).ptr, source);
|
||||
}
|
||||
|
||||
public static final void _wglCompileShader(IShaderGL obj) {
|
||||
ctx.compileShader(obj == null ? null : ((OpenGLObjects.ShaderGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final int _wglGetShaderi(IShaderGL obj, int param) {
|
||||
return ctx.getShaderParameteri(obj == null ? null : ((OpenGLObjects.ShaderGL)obj).ptr, param);
|
||||
}
|
||||
|
||||
public static final String _wglGetShaderInfoLog(IShaderGL obj) {
|
||||
return ctx.getShaderInfoLog(obj == null ? null : ((OpenGLObjects.ShaderGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglUseProgram(IProgramGL obj) {
|
||||
ctx.useProgram(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglAttachShader(IProgramGL obj, IShaderGL shader) {
|
||||
ctx.attachShader(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr,
|
||||
shader == null ? null : ((OpenGLObjects.ShaderGL)shader).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglDetachShader(IProgramGL obj, IShaderGL shader) {
|
||||
ctx.detachShader(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr,
|
||||
shader == null ? null : ((OpenGLObjects.ShaderGL)shader).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglLinkProgram(IProgramGL obj) {
|
||||
ctx.linkProgram(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final int _wglGetProgrami(IProgramGL obj, int param) {
|
||||
return ctx.getProgramParameteri(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr, param);
|
||||
}
|
||||
|
||||
public static final String _wglGetProgramInfoLog(IProgramGL obj) {
|
||||
return ctx.getProgramInfoLog(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglBindAttribLocation(IProgramGL obj, int index, String name) {
|
||||
ctx.bindAttribLocation(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr, index, name);
|
||||
}
|
||||
|
||||
public static final int _wglGetAttribLocation(IProgramGL obj, String name) {
|
||||
return ctx.getAttribLocation(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr, name);
|
||||
}
|
||||
|
||||
public static final void _wglDrawArrays(int mode, int first, int count) {
|
||||
ctx.drawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
public static final void _wglDrawArraysInstanced(int mode, int first, int count, int instanced) {
|
||||
ctx.drawArraysInstanced(mode, first, count, instanced);
|
||||
}
|
||||
|
||||
public static final void _wglDrawElements(int mode, int count, int type, int offset) {
|
||||
ctx.drawElements(mode, count, type, offset);
|
||||
}
|
||||
|
||||
public static final void _wglDrawElementsInstanced(int mode, int count, int type, int offset, int instanced) {
|
||||
ctx.drawElementsInstanced(mode, count, type, offset, instanced);
|
||||
}
|
||||
|
||||
public static final IUniformGL _wglGetUniformLocation(IProgramGL obj, String name) {
|
||||
return new OpenGLObjects.UniformGL(ctx.getUniformLocation(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr, name));
|
||||
}
|
||||
|
||||
public static final void _wglUniform1f(IUniformGL obj, float x) {
|
||||
ctx.uniform1f(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x);
|
||||
}
|
||||
|
||||
public static final void _wglUniform2f(IUniformGL obj, float x, float y) {
|
||||
ctx.uniform2f(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x, y);
|
||||
}
|
||||
|
||||
public static final void _wglUniform3f(IUniformGL obj, float x, float y, float z) {
|
||||
ctx.uniform3f(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x, y, z);
|
||||
}
|
||||
|
||||
public static final void _wglUniform4f(IUniformGL obj, float x, float y, float z, float w) {
|
||||
ctx.uniform4f(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x, y, z, w);
|
||||
}
|
||||
|
||||
public static final void _wglUniform1i(IUniformGL obj, int x) {
|
||||
ctx.uniform1i(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x);
|
||||
}
|
||||
|
||||
public static final void _wglUniform2i(IUniformGL obj, int x, int y) {
|
||||
ctx.uniform2i(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x, y);
|
||||
}
|
||||
|
||||
public static final void _wglUniform3i(IUniformGL obj, int x, int y, int z) {
|
||||
ctx.uniform3i(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x, y, z);
|
||||
}
|
||||
|
||||
public static final void _wglUniform4i(IUniformGL obj, int x, int y, int z, int w) {
|
||||
ctx.uniform4i(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, x, y, z, w);
|
||||
}
|
||||
|
||||
public static final void _wglUniformMatrix2fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
|
||||
ctx.uniformMatrix2fv(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, transpose,
|
||||
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
|
||||
}
|
||||
|
||||
public static final void _wglUniformMatrix3fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
|
||||
ctx.uniformMatrix3fv(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, transpose,
|
||||
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
|
||||
}
|
||||
|
||||
public static final void _wglUniformMatrix4fv(IUniformGL obj, boolean transpose, FloatBuffer mat) {
|
||||
ctx.uniformMatrix4fv(obj == null ? null : ((OpenGLObjects.UniformGL)obj).ptr, transpose,
|
||||
mat == null ? null : EaglerArrayBufferAllocator.getFloatArrayStupid(mat));
|
||||
}
|
||||
|
||||
public static final void _wglBindFramebuffer(int target, IFramebufferGL framebuffer) {
|
||||
ctx.bindFramebuffer(target, framebuffer == null ? PlatformRuntime.mainFramebuffer
|
||||
: ((OpenGLObjects.FramebufferGL) framebuffer).ptr);
|
||||
}
|
||||
|
||||
public static final int _wglCheckFramebufferStatus(int target) {
|
||||
return ctx.checkFramebufferStatus(target);
|
||||
}
|
||||
|
||||
public static final void _wglFramebufferTexture2D(int target, int attachment, int texTarget,
|
||||
ITextureGL texture, int level) {
|
||||
ctx.framebufferTexture2D(target, attachment, texTarget,
|
||||
texture == null ? null : ((OpenGLObjects.TextureGL)texture).ptr, level);
|
||||
}
|
||||
|
||||
public static final void _wglBlitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1,
|
||||
int dstX0, int dstY0, int dstX1, int dstY1, int bits, int filter) {
|
||||
ctx.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, bits, filter);
|
||||
}
|
||||
|
||||
public static final void _wglBindRenderbuffer(int target, IRenderbufferGL renderbuffer) {
|
||||
ctx.bindRenderbuffer(target,
|
||||
renderbuffer == null ? null : ((OpenGLObjects.RenderbufferGL)renderbuffer).ptr);
|
||||
}
|
||||
|
||||
public static final void _wglRenderbufferStorage(int target, int internalformat,
|
||||
int width, int height) {
|
||||
ctx.renderbufferStorage(target, internalformat, width, height);
|
||||
}
|
||||
|
||||
public static final void _wglFramebufferRenderbuffer(int target, int attachment,
|
||||
int renderbufferTarget, IRenderbufferGL renderbuffer) {
|
||||
ctx.framebufferRenderbuffer(target, attachment, renderbufferTarget,
|
||||
((OpenGLObjects.RenderbufferGL)renderbuffer).ptr);
|
||||
}
|
||||
|
||||
public static final String _wglGetString(int param) {
|
||||
if(hasDebugRenderInfoExt) {
|
||||
String s;
|
||||
switch(param) {
|
||||
case 0x1f00: // VENDOR
|
||||
s = ctx.getParameterString(0x9245); // UNMASKED_VENDOR_WEBGL
|
||||
if(s == null) {
|
||||
s = ctx.getParameterString(0x1f00); // VENDOR
|
||||
}
|
||||
return s;
|
||||
case 0x1f01: // RENDERER
|
||||
s = ctx.getParameterString(0x9246); // UNMASKED_RENDERER_WEBGL
|
||||
if(s == null) {
|
||||
s = ctx.getParameterString(0x1f01); // RENDERER
|
||||
}
|
||||
return s;
|
||||
default:
|
||||
return ctx.getParameterString(param);
|
||||
}
|
||||
}else {
|
||||
return ctx.getParameterString(param);
|
||||
}
|
||||
}
|
||||
|
||||
public static final int _wglGetInteger(int param) {
|
||||
return ctx.getParameteri(param);
|
||||
}
|
||||
|
||||
public static final int _wglGetError() {
|
||||
return ctx.getError();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,560 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSExceptions;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.ajax.XMLHttpRequest;
|
||||
import org.teavm.jso.browser.Window;
|
||||
import org.teavm.jso.canvas.CanvasRenderingContext2D;
|
||||
import org.teavm.jso.core.JSError;
|
||||
import org.teavm.jso.dom.css.CSSStyleDeclaration;
|
||||
import org.teavm.jso.dom.events.Event;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.dom.html.HTMLAnchorElement;
|
||||
import org.teavm.jso.dom.html.HTMLCanvasElement;
|
||||
import org.teavm.jso.dom.html.HTMLDocument;
|
||||
import org.teavm.jso.dom.html.HTMLElement;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.webaudio.MediaStream;
|
||||
import org.teavm.jso.webgl.WebGLFramebuffer;
|
||||
|
||||
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.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
|
||||
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.teavm.EPKLoader;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.EarlyLoadScreen;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass.EPKFileEntry;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContext;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class PlatformRuntime {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("BrowserRuntime");
|
||||
|
||||
public static Window win = null;
|
||||
public static HTMLDocument doc = null;
|
||||
public static HTMLElement parent = null;
|
||||
public static HTMLCanvasElement canvas = null;
|
||||
public static WebGL2RenderingContext webgl = null;
|
||||
|
||||
static WebGLFramebuffer mainFramebuffer = null;
|
||||
|
||||
public static void create() {
|
||||
win = Window.current();
|
||||
doc = win.getDocument();
|
||||
|
||||
logger.info("Creating main game canvas");
|
||||
|
||||
parent = doc.getElementById(MainClass.configRootElement);
|
||||
if(parent == null) {
|
||||
throw new RuntimeInitializationFailureException("Root element \"" + MainClass.configRootElement + "\" was not found in this document!");
|
||||
}
|
||||
|
||||
CSSStyleDeclaration style = parent.getStyle();
|
||||
style.setProperty("overflowX", "hidden");
|
||||
style.setProperty("overflowY", "hidden");
|
||||
|
||||
canvas = (HTMLCanvasElement) doc.createElement("canvas");
|
||||
|
||||
style = canvas.getStyle();
|
||||
style.setProperty("width", "100%");
|
||||
style.setProperty("height", "100%");
|
||||
style.setProperty("image-rendering", "pixelated");
|
||||
|
||||
double r = win.getDevicePixelRatio();
|
||||
int iw = parent.getClientWidth();
|
||||
int ih = parent.getClientHeight();
|
||||
int sw = (int)(r * iw);
|
||||
int sh = (int)(r * ih);
|
||||
|
||||
canvas.setWidth(sw);
|
||||
canvas.setHeight(sh);
|
||||
|
||||
parent.appendChild(canvas);
|
||||
|
||||
try {
|
||||
PlatformInput.initHooks(win, canvas);
|
||||
}catch(Throwable t) {
|
||||
throw new RuntimeInitializationFailureException("Exception while registering window event handlers", t);
|
||||
}
|
||||
|
||||
try {
|
||||
doc.exitPointerLock();
|
||||
}catch(Throwable t) {
|
||||
throw new PlatformIncompatibleException("Mouse cursor lock is not available on this device!");
|
||||
}
|
||||
|
||||
logger.info("Creating WebGL context");
|
||||
|
||||
JSObject webgl_ = canvas.getContext("webgl2", youEagler());
|
||||
if(webgl_ == null) {
|
||||
throw new PlatformIncompatibleException("WebGL 2.0 is not supported on this device!");
|
||||
}
|
||||
|
||||
webgl = (WebGL2RenderingContext) webgl_;
|
||||
PlatformOpenGL.setCurrentContext(webgl);
|
||||
|
||||
mainFramebuffer = webgl.createFramebuffer();
|
||||
PlatformInput.initFramebuffer(webgl, mainFramebuffer, sw, sh);
|
||||
|
||||
EarlyLoadScreen.paintScreen();
|
||||
|
||||
EPKFileEntry[] epkFiles = MainClass.configEPKFiles;
|
||||
|
||||
for(int i = 0; i < epkFiles.length; ++i) {
|
||||
String url = epkFiles[i].url;
|
||||
String logURL = url.startsWith("data:") ? "<data: " + url.length() + " chars>" : url;
|
||||
|
||||
logger.info("Downloading: {}", logURL);
|
||||
|
||||
ArrayBuffer epkFileData = downloadRemoteURI(url);
|
||||
|
||||
if(epkFileData == null) {
|
||||
throw new RuntimeInitializationFailureException("Could not download EPK file \"" + url + "\"");
|
||||
}
|
||||
|
||||
logger.info("Decompressing: {}", logURL);
|
||||
|
||||
try {
|
||||
EPKLoader.loadEPK(epkFileData, epkFiles[i].path, PlatformAssets.assets);
|
||||
}catch(Throwable t) {
|
||||
throw new RuntimeInitializationFailureException("Could not extract EPK file \"" + url + "\"", t);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Loaded {} resources from EPKs", PlatformAssets.assets.size());
|
||||
|
||||
byte[] finalLoadScreen = PlatformAssets.getResourceBytes("/assets/eagler/eagtek.png");
|
||||
|
||||
logger.info("Initializing sound engine...");
|
||||
|
||||
PlatformInput.pressAnyKeyScreen();
|
||||
|
||||
PlatformAudio.initialize();
|
||||
|
||||
if(finalLoadScreen != null) {
|
||||
EarlyLoadScreen.paintFinal(finalLoadScreen);
|
||||
}
|
||||
|
||||
logger.info("Platform initialization complete");
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "return {antialias: false, depth: false, powerPreference: \"high-performance\", desynchronized: true, preserveDrawingBuffer: false, premultipliedAlpha: false, alpha: false};")
|
||||
public static native JSObject youEagler();
|
||||
|
||||
public static class RuntimeInitializationFailureException extends IllegalStateException {
|
||||
|
||||
public RuntimeInitializationFailureException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public RuntimeInitializationFailureException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PlatformIncompatibleException extends IllegalStateException {
|
||||
|
||||
public PlatformIncompatibleException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
logger.fatal("Game tried to destroy the context! Browser runtime can't do that");
|
||||
}
|
||||
|
||||
public static EnumPlatformType getPlatformType() {
|
||||
return EnumPlatformType.JAVASCRIPT;
|
||||
}
|
||||
|
||||
public static EnumPlatformAgent getPlatformAgent() {
|
||||
return EnumPlatformAgent.getFromUA(getUserAgentString());
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "return window.navigator.userAgent;")
|
||||
public static native String getUserAgentString();
|
||||
|
||||
public static EnumPlatformOS getPlatformOS() {
|
||||
return EnumPlatformOS.getFromUA(getUserAgentString());
|
||||
}
|
||||
|
||||
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 EaglerArrayBufferAllocator.allocateByteBuffer(length);
|
||||
}
|
||||
|
||||
public static IntBuffer allocateIntBuffer(int length) {
|
||||
return EaglerArrayBufferAllocator.allocateIntBuffer(length);
|
||||
}
|
||||
|
||||
public static FloatBuffer allocateFloatBuffer(int length) {
|
||||
return EaglerArrayBufferAllocator.allocateFloatBuffer(length);
|
||||
}
|
||||
|
||||
public static void freeByteBuffer(ByteBuffer byteBuffer) {
|
||||
|
||||
}
|
||||
|
||||
public static void freeIntBuffer(IntBuffer intBuffer) {
|
||||
|
||||
}
|
||||
|
||||
public static void freeFloatBuffer(FloatBuffer floatBuffer) {
|
||||
|
||||
}
|
||||
|
||||
public static void downloadRemoteURI(String assetPackageURI, final Consumer<ArrayBuffer> cb) {
|
||||
downloadRemoteURI(assetPackageURI, new AsyncCallback<ArrayBuffer>() {
|
||||
@Override
|
||||
public void complete(ArrayBuffer result) {
|
||||
cb.accept(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
e.printStackTrace();
|
||||
cb.accept(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Async
|
||||
public static native ArrayBuffer downloadRemoteURI(String assetPackageURI);
|
||||
|
||||
private static void downloadRemoteURI(String assetPackageURI, final AsyncCallback<ArrayBuffer> cb) {
|
||||
final XMLHttpRequest request = XMLHttpRequest.create();
|
||||
request.setResponseType("arraybuffer");
|
||||
request.open("GET", assetPackageURI, true);
|
||||
|
||||
TeaVMUtils.addEventListener(request, "load", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
int stat = request.getStatus();
|
||||
if(stat == 0 || (stat >= 200 && stat < 400)) {
|
||||
cb.complete((ArrayBuffer)request.getResponse());
|
||||
}else {
|
||||
cb.complete(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
TeaVMUtils.addEventListener(request, "error", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
cb.complete(null);
|
||||
}
|
||||
});
|
||||
|
||||
request.send();
|
||||
}
|
||||
|
||||
public static boolean isDebugRuntime() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void writeCrashReport(String crashDump) {
|
||||
MainClass.showCrashScreen(crashDump);
|
||||
}
|
||||
|
||||
public static void removeEventHandlers() {
|
||||
try {
|
||||
PlatformInput.removeEventHandlers();
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void getStackTrace(Throwable t, Consumer<String> ret) {
|
||||
JSObject o = JSExceptions.getJSException(t);
|
||||
if(o != null) {
|
||||
try {
|
||||
JSError err = o.cast();
|
||||
String stack = err.getStack();
|
||||
if(stack != null) {
|
||||
String[] stackElements = stack.split("[\\r\\n]+");
|
||||
if(stackElements.length > 0) {
|
||||
for(int i = 0; i < stackElements.length; ++i) {
|
||||
String str = stackElements[i].trim();
|
||||
if(str.startsWith("at ")) {
|
||||
str = str.substring(3).trim();
|
||||
}
|
||||
ret.accept(str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}catch(Throwable tt) {
|
||||
ret.accept("[ error: " + t.toString() + " ]");
|
||||
}
|
||||
}
|
||||
getFallbackStackTrace(t, ret);
|
||||
}
|
||||
|
||||
private static void getFallbackStackTrace(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]");
|
||||
}
|
||||
}
|
||||
|
||||
@JSBody(params = { "o" }, script = "console.error(o);")
|
||||
private static native void printNativeExceptionToConsole(JSObject o);
|
||||
|
||||
public static boolean printJSExceptionIfBrowser(Throwable t) {
|
||||
if(t != null) {
|
||||
JSObject o = JSExceptions.getJSException(t);
|
||||
if(o != null) {
|
||||
printNativeExceptionToConsole(o);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void exit() {
|
||||
logger.fatal("Game is attempting to exit!");
|
||||
}
|
||||
|
||||
public static void setThreadName(String string) {
|
||||
// no teavm support
|
||||
}
|
||||
|
||||
public static long maxMemory() {
|
||||
return 1073741824l;
|
||||
}
|
||||
|
||||
public static long totalMemory() {
|
||||
return 1073741824l;
|
||||
}
|
||||
|
||||
public static long freeMemory() {
|
||||
return 1073741824l;
|
||||
}
|
||||
|
||||
public static String getCallingClass(int backTrace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@JSBody(params = { }, script = "return window.location.protocol && window.location.protocol.toLowerCase().startsWith(\"https\");")
|
||||
public static native boolean requireSSL();
|
||||
|
||||
public static IClientConfigAdapter getClientConfigAdapter() {
|
||||
return TeaVMClientConfigAdapter.instance;
|
||||
}
|
||||
|
||||
private static boolean canRec = false;
|
||||
private static boolean recording = false;
|
||||
private static JSObject mediaRec = null;
|
||||
private static HTMLCanvasElement recCanvas = null;
|
||||
private static CanvasRenderingContext2D recCtx = null;
|
||||
private static MediaStream recStream = null;
|
||||
|
||||
public static boolean isRec() {
|
||||
return recording && canRec;
|
||||
}
|
||||
|
||||
@JSBody(params = { "canvas", "audio" }, script = "const stream = canvas.captureStream(); stream.addTrack(audio.getTracks()[0]); return stream;")
|
||||
private static native MediaStream captureStreamAndAddAudio(HTMLCanvasElement canvas, MediaStream audio);
|
||||
|
||||
@JSBody(params = { "stream" }, script = "const rec = new MediaRecorder(stream, { mimeType: MediaRecorder.isTypeSupported(\"video/webm;codecs=vp9,opus\") ? \"video/webm;codecs=vp9,opus\" : \"video/webm\" }); rec.start(); return rec;")
|
||||
private static native JSObject createMediaRecorder(MediaStream stream);
|
||||
|
||||
@JSBody(params = { "rec" }, script = "rec.stop();")
|
||||
private static native void stopRec(JSObject rec);
|
||||
|
||||
@JSBody(params = { }, script = "return \"MediaRecorder\" in window;")
|
||||
private static native boolean canRec();
|
||||
|
||||
@JSFunctor
|
||||
private static interface RecUrlHandler extends JSObject {
|
||||
void onUrl(String url);
|
||||
}
|
||||
|
||||
@JSBody(params = { "e", "duration", "cb" }, script = "if (\"ysFixWebmDuration\" in window) { ysFixWebmDuration(e.data, duration, function(b) { cb(URL.createObjectURL(b)); }); } else { cb(URL.createObjectURL(e.data)); }")
|
||||
private static native void getRecUrl(Event e, int duration, RecUrlHandler cb);
|
||||
|
||||
public static boolean recSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getRecText() {
|
||||
if (recording && !canRec) {
|
||||
return "recording.unsupported";
|
||||
}
|
||||
return recording ? "recording.stop" : "recording.start";
|
||||
}
|
||||
|
||||
private static void recFrame() {
|
||||
if (mediaRec != null) {
|
||||
int w = PlatformRuntime.canvas.getWidth();
|
||||
int h = PlatformRuntime.canvas.getHeight();
|
||||
if (recCanvas.getWidth() != w || recCanvas.getHeight() != h) {
|
||||
recCanvas.setWidth(w);
|
||||
recCanvas.setHeight(h);
|
||||
}
|
||||
recCtx.drawImage(canvas, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void onRecFrame() {
|
||||
if (recording) {
|
||||
recFrame();
|
||||
long t = System.currentTimeMillis();
|
||||
Window.requestAnimationFrame(timestamp -> {
|
||||
long d = (1000 / 30) - (System.currentTimeMillis() - t);
|
||||
if (d <= 0) {
|
||||
onRecFrame();
|
||||
} else {
|
||||
Window.setTimeout(PlatformRuntime::onRecFrame, d);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
private static interface MediaHandler extends JSObject {
|
||||
void onMedia(MediaStream stream);
|
||||
}
|
||||
|
||||
@JSBody(params = { "cb" }, script = "if (\"navigator\" in window && \"mediaDevices\" in window.navigator && \"getUserMedia\" in window.navigator.mediaDevices) { try { window.navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function(stream) { cb(stream); }).catch(function(err) { console.error(err); cb(null); }); } catch(e) { console.error(\"getUserMedia Error!\"); cb(null); } } else { console.error(\"No getUserMedia!\"); cb(null); }")
|
||||
private static native void getMic0(MediaHandler cb);
|
||||
|
||||
@Async
|
||||
private static native MediaStream getMic1();
|
||||
|
||||
private static void getMic1(AsyncCallback<MediaStream> cb) {
|
||||
getMic0(cb::complete);
|
||||
}
|
||||
|
||||
private static boolean canMic = true;
|
||||
private static MediaStream mic = null;
|
||||
|
||||
protected static MediaStream getMic() {
|
||||
if (canMic) {
|
||||
if (mic == null) {
|
||||
mic = getMic1();
|
||||
if (mic == null) {
|
||||
canMic = false;
|
||||
return null;
|
||||
}
|
||||
return mic;
|
||||
}
|
||||
return mic;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");
|
||||
private static final Date dateInstance = new Date();
|
||||
|
||||
public static void toggleRec() {
|
||||
if (recording && !canRec) {
|
||||
return;
|
||||
}
|
||||
recording = !recording;
|
||||
if (recording) {
|
||||
if (!canRec) {
|
||||
canRec = canRec();
|
||||
if (!canRec) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (recCanvas == null) {
|
||||
recCanvas = (HTMLCanvasElement) Window.current().getDocument().createElement("canvas");
|
||||
recCtx = (CanvasRenderingContext2D) recCanvas.getContext("2d");
|
||||
PlatformAudio.initRecDest();
|
||||
recStream = captureStreamAndAddAudio(recCanvas, PlatformAudio.getRecStream());
|
||||
}
|
||||
mediaRec = createMediaRecorder(recStream);
|
||||
long startTime = System.currentTimeMillis();
|
||||
TeaVMUtils.addEventListener(mediaRec, "dataavailable", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
getRecUrl(evt, (int) (System.currentTimeMillis() - startTime), url -> {
|
||||
HTMLAnchorElement a = (HTMLAnchorElement) doc.createElement("a");
|
||||
dateInstance.setTime(startTime);
|
||||
a.setDownload(EaglercraftVersion.mainMenuStringB + " - " + EaglerProfile.getName() + " - " + fmt.format(dateInstance) + ".webm");
|
||||
a.setHref(url);
|
||||
a.click();
|
||||
});
|
||||
}
|
||||
});
|
||||
onRecFrame();
|
||||
} else {
|
||||
stopRec(mediaRec);
|
||||
mediaRec = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.DataView;
|
||||
import org.teavm.jso.typedarrays.Float32Array;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class EaglerArrayBufferAllocator {
|
||||
|
||||
public static class WrongBufferClassType extends RuntimeException {
|
||||
public WrongBufferClassType(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuffer allocateByteBuffer(int size) {
|
||||
return new EaglerArrayByteBuffer(DataView.create(ArrayBuffer.create(size)));
|
||||
}
|
||||
|
||||
public static IntBuffer allocateIntBuffer(int size) {
|
||||
return new EaglerArrayIntBuffer(DataView.create(ArrayBuffer.create(size << 2)));
|
||||
}
|
||||
|
||||
public static FloatBuffer allocateFloatBuffer(int size) {
|
||||
return new EaglerArrayFloatBuffer(DataView.create(ArrayBuffer.create(size << 2)));
|
||||
}
|
||||
|
||||
public static DataView getDataView(ByteBuffer buffer) {
|
||||
if(buffer instanceof EaglerArrayByteBuffer) {
|
||||
EaglerArrayByteBuffer b = (EaglerArrayByteBuffer)buffer;
|
||||
DataView d = b.dataView;
|
||||
int p = b.position;
|
||||
int l = b.limit;
|
||||
if(p == 0 && l == b.capacity) {
|
||||
return d;
|
||||
}else {
|
||||
int i = d.getByteOffset();
|
||||
return DataView.create(d.getBuffer(), i + p, l - p);
|
||||
}
|
||||
}else {
|
||||
throw notEagler(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static Uint8Array getDataViewStupid(ByteBuffer buffer) {
|
||||
if(buffer instanceof EaglerArrayByteBuffer) {
|
||||
EaglerArrayByteBuffer b = (EaglerArrayByteBuffer)buffer;
|
||||
DataView d = b.dataView;
|
||||
int p = b.position;
|
||||
int l = b.limit;
|
||||
int i = d.getByteOffset();
|
||||
return Uint8Array.create(d.getBuffer(), i + p, l - p);
|
||||
}else {
|
||||
throw notEagler(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static DataView getDataView(IntBuffer buffer) {
|
||||
if(buffer instanceof EaglerArrayIntBuffer) {
|
||||
EaglerArrayIntBuffer b = (EaglerArrayIntBuffer)buffer;
|
||||
DataView d = b.dataView;
|
||||
int p = b.position;
|
||||
int l = b.limit;
|
||||
if(p == 0 && l == b.capacity) {
|
||||
return d;
|
||||
}else {
|
||||
int i = d.getByteOffset();
|
||||
return DataView.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
|
||||
}
|
||||
}else {
|
||||
throw notEagler(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static Uint8Array getDataViewStupid(IntBuffer buffer) {
|
||||
if(buffer instanceof EaglerArrayIntBuffer) {
|
||||
EaglerArrayIntBuffer b = (EaglerArrayIntBuffer)buffer;
|
||||
DataView d = b.dataView;
|
||||
int p = b.position;
|
||||
int l = b.limit;
|
||||
int i = d.getByteOffset();
|
||||
return Uint8Array.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
|
||||
}else {
|
||||
throw notEagler(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static DataView getDataView(FloatBuffer buffer) {
|
||||
if(buffer instanceof EaglerArrayFloatBuffer) {
|
||||
EaglerArrayFloatBuffer b = (EaglerArrayFloatBuffer)buffer;
|
||||
DataView d = b.dataView;
|
||||
int p = b.position;
|
||||
int l = b.limit;
|
||||
if(p == 0 && l == b.capacity) {
|
||||
return d;
|
||||
}else {
|
||||
int i = d.getByteOffset();
|
||||
return DataView.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
|
||||
}
|
||||
}else {
|
||||
throw notEagler(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static Uint8Array getDataViewStupid(FloatBuffer buffer) {
|
||||
if(buffer instanceof EaglerArrayFloatBuffer) {
|
||||
EaglerArrayFloatBuffer b = (EaglerArrayFloatBuffer)buffer;
|
||||
DataView d = b.dataView;
|
||||
int p = b.position;
|
||||
int l = b.limit;
|
||||
int i = d.getByteOffset();
|
||||
return Uint8Array.create(d.getBuffer(), i + (p << 2), (l - p) << 2);
|
||||
}else {
|
||||
throw notEagler(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static Float32Array getFloatArrayStupid(FloatBuffer buffer) {
|
||||
if(buffer instanceof EaglerArrayFloatBuffer) {
|
||||
EaglerArrayFloatBuffer b = (EaglerArrayFloatBuffer)buffer;
|
||||
DataView d = b.dataView;
|
||||
int p = b.position;
|
||||
int l = b.limit;
|
||||
int i = d.getByteOffset();
|
||||
return Float32Array.create(d.getBuffer(), i + p, l - p);
|
||||
}else {
|
||||
throw notEagler(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static WrongBufferClassType notEagler(Object clazz) {
|
||||
return new WrongBufferClassType("Tried to pass a " + clazz.getClass().getSimpleName() + " which is not a native eagler buffer");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,439 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.DataView;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class EaglerArrayByteBuffer implements ByteBuffer {
|
||||
|
||||
final DataView dataView;
|
||||
|
||||
final int capacity;
|
||||
int position;
|
||||
int limit;
|
||||
int mark;
|
||||
|
||||
static final DataView ZERO_LENGTH_BUFFER = DataView.create(ArrayBuffer.create(0));
|
||||
|
||||
EaglerArrayByteBuffer(DataView dataView) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength();
|
||||
this.position = 0;
|
||||
this.limit = this.capacity;
|
||||
this.mark = -1;
|
||||
}
|
||||
|
||||
EaglerArrayByteBuffer(DataView dataView, int position, int limit, int mark) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength();
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
}
|
||||
|
||||
@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 limit > position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer slice() {
|
||||
int o = dataView.getByteOffset();
|
||||
return new EaglerArrayByteBuffer(DataView.create(dataView.getBuffer(), o + position, limit - position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer duplicate() {
|
||||
return new EaglerArrayByteBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer asReadOnlyBuffer() {
|
||||
return new EaglerArrayByteBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
return dataView.getInt8(position++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setInt8(position++, b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getInt8(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(int index, byte b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setInt8(index, b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer get(byte[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dst[offset + i] = dataView.getInt8(position + i);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer get(byte[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
for(int i = 0; i < dst.length; ++i) {
|
||||
dst[position + i] = dataView.getInt8(position + i);
|
||||
}
|
||||
position += dst.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(ByteBuffer src) {
|
||||
if(src instanceof EaglerArrayByteBuffer) {
|
||||
EaglerArrayByteBuffer c = (EaglerArrayByteBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
int o = c.dataView.getByteOffset();
|
||||
Uint8Array.create(dataView.getBuffer()).set(
|
||||
Uint8Array.create(c.dataView.getBuffer(), o + c.position, c.limit - c.position),
|
||||
dataView.getByteOffset() + position);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
dataView.setInt8(position + l, src.get());
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dataView.setInt8(position + i, src[offset + i]);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
dataView.set(src, position);
|
||||
position += src.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer compact() {
|
||||
if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
|
||||
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
|
||||
if(position == limit) {
|
||||
return new EaglerArrayByteBuffer(ZERO_LENGTH_BUFFER);
|
||||
}
|
||||
|
||||
int o = dataView.getByteOffset();
|
||||
|
||||
Uint8Array dst = Uint8Array.create(ArrayBuffer.create(limit - position));
|
||||
dst.set(Uint8Array.create(dataView.getBuffer(), o + position, limit - position));
|
||||
|
||||
return new EaglerArrayByteBuffer(DataView.create(dst.getBuffer()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar() {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
char c = (char)dataView.getUint16(position, true);
|
||||
position += 2;
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putChar(char value) {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setUint16(position, (short)value, true);
|
||||
position += 2;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(int index) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return (char)dataView.getUint16(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putChar(int index, char value) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setUint16(index, value, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
short s = dataView.getInt16(position, true);
|
||||
position += 2;
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putShort(short value) {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setInt16(position, value, true);
|
||||
position += 2;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int index) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getInt16(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putShort(int index, short value) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setInt16(index, value, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer asShortBuffer() {
|
||||
return new EaglerArrayShortBuffer(dataView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
int i = dataView.getInt32(position, true);
|
||||
position += 4;
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putInt(int value) {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setInt32(position, value, true);
|
||||
position += 4;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int index) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getInt32(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putInt(int index, int value) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setInt32(index, value, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer asIntBuffer() {
|
||||
return new EaglerArrayIntBuffer(dataView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
long l = dataView.getUint32(position) | ((long) dataView.getUint8(position + 4) << 32)
|
||||
| ((long) dataView.getUint8(position + 5) << 40) | ((long) dataView.getUint8(position + 6) << 48)
|
||||
| ((long) dataView.getUint8(position + 7) << 56);
|
||||
position += 8;
|
||||
return l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putLong(long value) {
|
||||
if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setUint32(position, (int) (value & 0xFFFFFFFF), true);
|
||||
dataView.setUint8(position + 4, (short) ((value >> 32) & 0xFF));
|
||||
dataView.setUint8(position + 5, (short) ((value >> 40) & 0xFF));
|
||||
dataView.setUint8(position + 6, (short) ((value >> 48) & 0xFF));
|
||||
dataView.setUint8(position + 7, (short) ((value >> 56) & 0xFF));
|
||||
position += 8;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int index) {
|
||||
if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getUint32(index, true) | ((long) dataView.getUint8(index + 4) << 32)
|
||||
| ((long) dataView.getUint8(index + 5) << 40) | ((long) dataView.getUint8(index + 6) << 48)
|
||||
| ((long) dataView.getUint8(index + 7) << 56);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putLong(int index, long value) {
|
||||
if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setUint32(index, (int) (value & 0xFFFFFFFF), true);
|
||||
dataView.setUint8(index + 4, (short) ((value >> 32) & 0xFF));
|
||||
dataView.setUint8(index + 5, (short) ((value >> 40) & 0xFF));
|
||||
dataView.setUint8(index + 6, (short) ((value >> 48) & 0xFF));
|
||||
dataView.setUint8(index + 7, (short) ((value >> 56) & 0xFF));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
float f = dataView.getFloat32(position, true);
|
||||
position += 4;
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putFloat(float value) {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setFloat32(position, value, true);
|
||||
position += 4;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int index) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getFloat32(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putFloat(int index, float value) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setFloat32(index, value, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer asFloatBuffer() {
|
||||
return new EaglerArrayFloatBuffer(dataView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mark() {
|
||||
mark = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new ArrayIndexOutOfBoundsException("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 new ArrayIndexOutOfBoundsException(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,287 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.DataView;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class EaglerArrayFloatBuffer implements FloatBuffer {
|
||||
|
||||
final DataView dataView;
|
||||
|
||||
final int capacity;
|
||||
int position;
|
||||
int limit;
|
||||
int mark;
|
||||
|
||||
private static final int SHIFT = 2;
|
||||
|
||||
EaglerArrayFloatBuffer(DataView dataView) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength() >> SHIFT;
|
||||
this.position = 0;
|
||||
this.limit = this.capacity;
|
||||
this.mark = -1;
|
||||
}
|
||||
|
||||
EaglerArrayFloatBuffer(DataView dataView, int position, int limit, int mark) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength() >> SHIFT;
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
}
|
||||
|
||||
@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 isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer slice() {
|
||||
int o = dataView.getByteOffset();
|
||||
return new EaglerArrayFloatBuffer(DataView.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer duplicate() {
|
||||
return new EaglerArrayFloatBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer asReadOnlyBuffer() {
|
||||
return new EaglerArrayFloatBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
return dataView.getFloat32((position++) << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setFloat32((position++) << SHIFT, b, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getFloat32(index << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(int index, float b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setFloat32(index << SHIFT, b, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getElement(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getFloat32(index << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, float value) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setFloat32(index << SHIFT, value, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer get(float[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dst[offset + i] = dataView.getFloat32((position + i) << SHIFT, true);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer get(float[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
for(int i = 0; i < dst.length; ++i) {
|
||||
dst[i] = dataView.getFloat32((position + i) << SHIFT, true);
|
||||
}
|
||||
position += dst.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(FloatBuffer src) {
|
||||
if(src instanceof EaglerArrayFloatBuffer) {
|
||||
EaglerArrayFloatBuffer c = (EaglerArrayFloatBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
int o = c.dataView.getByteOffset();
|
||||
Uint8Array.create(dataView.getBuffer()).set(
|
||||
Uint8Array.create(c.dataView.getBuffer(), o + (c.position << SHIFT), (c.limit - c.position) << SHIFT),
|
||||
dataView.getByteOffset() + (position << SHIFT));
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
dataView.setFloat32((position + l) << SHIFT, src.get(), true);
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dataView.setFloat32((position + i) << SHIFT, src[offset + i], true);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
for(int i = 0; i < src.length; ++i) {
|
||||
dataView.setFloat32((position + i) << SHIFT, src[i], true);
|
||||
}
|
||||
position += src.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer compact() {
|
||||
if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
|
||||
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
|
||||
if(position == limit) {
|
||||
return new EaglerArrayFloatBuffer(EaglerArrayByteBuffer.ZERO_LENGTH_BUFFER);
|
||||
}
|
||||
|
||||
int o = dataView.getByteOffset();
|
||||
|
||||
Uint8Array dst = Uint8Array.create(ArrayBuffer.create((limit - position) << SHIFT));
|
||||
dst.set(Uint8Array.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
|
||||
|
||||
return new EaglerArrayFloatBuffer(DataView.create(dst.getBuffer()));
|
||||
}
|
||||
|
||||
@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 ArrayIndexOutOfBoundsException("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 new ArrayIndexOutOfBoundsException(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,287 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.DataView;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class EaglerArrayIntBuffer implements IntBuffer {
|
||||
|
||||
final DataView dataView;
|
||||
|
||||
final int capacity;
|
||||
int position;
|
||||
int limit;
|
||||
int mark;
|
||||
|
||||
private static final int SHIFT = 2;
|
||||
|
||||
EaglerArrayIntBuffer(DataView dataView) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength() >> SHIFT;
|
||||
this.position = 0;
|
||||
this.limit = this.capacity;
|
||||
this.mark = -1;
|
||||
}
|
||||
|
||||
EaglerArrayIntBuffer(DataView dataView, int position, int limit, int mark) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength() >> SHIFT;
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
}
|
||||
|
||||
@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 isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer slice() {
|
||||
int o = dataView.getByteOffset();
|
||||
return new EaglerArrayIntBuffer(DataView.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer duplicate() {
|
||||
return new EaglerArrayIntBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer asReadOnlyBuffer() {
|
||||
return new EaglerArrayIntBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
return dataView.getInt32((position++) << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setInt32((position++) << SHIFT, b, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getInt32(index << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int index, int b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setInt32(index << SHIFT, b, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getElement(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getInt32(index << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, int value) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setInt32(index << SHIFT, value, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer get(int[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dst[offset + i] = dataView.getInt32((position + i) << SHIFT, true);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer get(int[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
for(int i = 0; i < dst.length; ++i) {
|
||||
dst[i] = dataView.getInt32((position + i) << SHIFT, true);
|
||||
}
|
||||
position += dst.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(IntBuffer src) {
|
||||
if(src instanceof EaglerArrayIntBuffer) {
|
||||
EaglerArrayIntBuffer c = (EaglerArrayIntBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
int o = c.dataView.getByteOffset();
|
||||
Uint8Array.create(dataView.getBuffer()).set(
|
||||
Uint8Array.create(c.dataView.getBuffer(), o + (c.position << SHIFT), (c.limit - c.position) << SHIFT),
|
||||
dataView.getByteOffset() + (position << SHIFT));
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
dataView.setInt32((position + l) << SHIFT, src.get(), true);
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dataView.setInt32((position + i) << SHIFT, src[offset + i], true);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
for(int i = 0; i < src.length; ++i) {
|
||||
dataView.setInt32((position + i) << SHIFT, src[i], true);
|
||||
}
|
||||
position += src.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer compact() {
|
||||
if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
|
||||
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
|
||||
if(position == limit) {
|
||||
return new EaglerArrayIntBuffer(EaglerArrayByteBuffer.ZERO_LENGTH_BUFFER);
|
||||
}
|
||||
|
||||
int o = dataView.getByteOffset();
|
||||
|
||||
Uint8Array dst = Uint8Array.create(ArrayBuffer.create((limit - position) << SHIFT));
|
||||
dst.set(Uint8Array.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
|
||||
|
||||
return new EaglerArrayIntBuffer(DataView.create(dst.getBuffer()));
|
||||
}
|
||||
|
||||
@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 ArrayIndexOutOfBoundsException("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 new ArrayIndexOutOfBoundsException(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,287 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.DataView;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class EaglerArrayShortBuffer implements ShortBuffer {
|
||||
|
||||
final DataView dataView;
|
||||
|
||||
final int capacity;
|
||||
int position;
|
||||
int limit;
|
||||
int mark;
|
||||
|
||||
private static final int SHIFT = 1;
|
||||
|
||||
EaglerArrayShortBuffer(DataView dataView) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength() >> SHIFT;
|
||||
this.position = 0;
|
||||
this.limit = this.capacity;
|
||||
this.mark = -1;
|
||||
}
|
||||
|
||||
EaglerArrayShortBuffer(DataView dataView, int position, int limit, int mark) {
|
||||
this.dataView = dataView;
|
||||
this.capacity = dataView.getByteLength() >> SHIFT;
|
||||
this.position = position;
|
||||
this.limit = limit;
|
||||
this.mark = mark;
|
||||
}
|
||||
|
||||
@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 isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer slice() {
|
||||
int o = dataView.getByteOffset();
|
||||
return new EaglerArrayShortBuffer(DataView.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer duplicate() {
|
||||
return new EaglerArrayShortBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer asReadOnlyBuffer() {
|
||||
return new EaglerArrayShortBuffer(dataView, position, limit, mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
return dataView.getInt16((position++) << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
dataView.setInt16((position++) << SHIFT, b, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getInt16(index << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(int index, short b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setInt16(index << SHIFT, b, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getElement(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
return dataView.getInt16(index << SHIFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, short value) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
dataView.setInt16(index << SHIFT, value, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer get(short[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dst[offset + i] = dataView.getInt16((position + i) << SHIFT, true);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer get(short[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
for(int i = 0; i < dst.length; ++i) {
|
||||
dst[i] = dataView.getInt16((position + i) << SHIFT, true);
|
||||
}
|
||||
position += dst.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(ShortBuffer src) {
|
||||
if(src instanceof EaglerArrayShortBuffer) {
|
||||
EaglerArrayShortBuffer c = (EaglerArrayShortBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
int o = c.dataView.getByteOffset();
|
||||
Uint8Array.create(dataView.getBuffer()).set(
|
||||
Uint8Array.create(c.dataView.getBuffer(), o + (c.position << SHIFT), (c.limit - c.position) << SHIFT),
|
||||
dataView.getByteOffset() + (position << SHIFT));
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
dataView.setInt16((position + l) << SHIFT, src.get(), true);
|
||||
}
|
||||
position += l;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
for(int i = 0; i < length; ++i) {
|
||||
dataView.setInt16((position + i) << SHIFT, src[offset + i], true);
|
||||
}
|
||||
position += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
for(int i = 0; i < src.length; ++i) {
|
||||
dataView.setInt16((position + i) << SHIFT, src[i], true);
|
||||
}
|
||||
position += src.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer compact() {
|
||||
if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
|
||||
if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
|
||||
if(position == limit) {
|
||||
return new EaglerArrayShortBuffer(EaglerArrayByteBuffer.ZERO_LENGTH_BUFFER);
|
||||
}
|
||||
|
||||
int o = dataView.getByteOffset();
|
||||
|
||||
Uint8Array dst = Uint8Array.create(ArrayBuffer.create((limit - position) << SHIFT));
|
||||
dst.set(Uint8Array.create(dataView.getBuffer(), o + (position << SHIFT), (limit - position) << SHIFT));
|
||||
|
||||
return new EaglerArrayShortBuffer(DataView.create(dst.getBuffer()));
|
||||
}
|
||||
|
||||
@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 ArrayIndexOutOfBoundsException("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 new ArrayIndexOutOfBoundsException(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
@JSFunctor
|
||||
public interface EventHandler extends JSObject {
|
||||
void handleEvent();
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
public interface IDBCountRequest extends IDBRequest {
|
||||
@JSProperty
|
||||
int getResult();
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSMethod;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
public interface IDBCursor extends JSObject {
|
||||
String DIRECTION_NEXT = "next";
|
||||
|
||||
String DIRECTION_NEXT_UNIQUE = "nextunique";
|
||||
|
||||
String DIRECTION_PREVIOUS = "prev";
|
||||
|
||||
String DIRECTION_PREVIOUS_UNIQUE = "prevunique";
|
||||
|
||||
@JSProperty
|
||||
IDBCursorSource getSource();
|
||||
|
||||
@JSProperty
|
||||
String getDirection();
|
||||
|
||||
@JSProperty
|
||||
JSObject getKey();
|
||||
|
||||
@JSProperty
|
||||
JSObject getValue();
|
||||
|
||||
@JSProperty
|
||||
JSObject getPrimaryKey();
|
||||
|
||||
IDBRequest update(JSObject value);
|
||||
|
||||
void advance(int count);
|
||||
|
||||
@JSMethod("continue")
|
||||
void doContinue();
|
||||
|
||||
IDBRequest delete();
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
public interface IDBCursorRequest extends IDBRequest {
|
||||
@JSProperty
|
||||
IDBCursor getResult();
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
public interface IDBCursorSource extends JSObject {
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.dom.events.EventTarget;
|
||||
|
||||
public interface IDBDatabase extends EventTarget {
|
||||
String TRANSACTION_READONLY = "readonly";
|
||||
|
||||
String TRANSACTION_READWRITE = "readwrite";
|
||||
|
||||
String TRANSACTION_VERSIONCHANGE = "versionchange";
|
||||
|
||||
@JSProperty
|
||||
String getName();
|
||||
|
||||
@JSProperty
|
||||
int getVersion();
|
||||
|
||||
@JSProperty
|
||||
String[] getObjectStoreNames();
|
||||
|
||||
IDBObjectStore createObjectStore(String name, IDBObjectStoreParameters optionalParameters);
|
||||
|
||||
IDBObjectStore createObjectStore(String name);
|
||||
|
||||
void deleteObjectStore(String name);
|
||||
|
||||
IDBTransaction transaction(String storeName, String transactionMode);
|
||||
|
||||
IDBTransaction transaction(String storeName);
|
||||
|
||||
IDBTransaction transaction(String[] storeNames, String transactionMode);
|
||||
|
||||
IDBTransaction transaction(String[] storeNames);
|
||||
|
||||
void close();
|
||||
|
||||
@JSProperty("onabort")
|
||||
void setOnAbort(EventHandler handler);
|
||||
|
||||
@JSProperty("onerror")
|
||||
void setOnError(EventHandler handler);
|
||||
|
||||
@JSProperty("onversionchange")
|
||||
void setOnVersionChange(EventHandler handler);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
public abstract class IDBError implements JSObject {
|
||||
@JSProperty
|
||||
public abstract String getName();
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
public abstract class IDBFactory implements JSObject {
|
||||
public static boolean isSupported() {
|
||||
return !getInstanceImpl().isUndefined();
|
||||
}
|
||||
|
||||
@JSBody(script = "return typeof this === 'undefined';")
|
||||
private native boolean isUndefined();
|
||||
|
||||
public static IDBFactory getInstance() {
|
||||
IDBFactory factory = getInstanceImpl();
|
||||
if (!factory.isUndefined()) {
|
||||
throw new IllegalStateException("IndexedDB is not supported in this browser");
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
@JSBody(script = "return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || "
|
||||
+ "window.msIndexedDB;")
|
||||
static native IDBFactory getInstanceImpl();
|
||||
|
||||
public abstract IDBOpenDBRequest open(String name, int version);
|
||||
|
||||
public abstract IDBOpenDBRequest deleteDatabase(String name);
|
||||
|
||||
public abstract int cmp(JSObject a, JSObject b);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
public interface IDBGetRequest extends IDBRequest {
|
||||
@JSProperty
|
||||
JSObject getResult();
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
|
||||
public abstract class IDBIndex implements JSObject, IDBCursorSource {
|
||||
@JSProperty
|
||||
public abstract String getName();
|
||||
|
||||
@JSProperty("keyPath")
|
||||
abstract JSObject getKeyPathImpl();
|
||||
|
||||
public final String[] getKeyPath() {
|
||||
JSObject result = getKeyPathImpl();
|
||||
if (JSString.isInstance(result)) {
|
||||
return new String[] { result.<JSString>cast().stringValue() };
|
||||
} else {
|
||||
return unwrapStringArray(result);
|
||||
}
|
||||
}
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return this;")
|
||||
private native String[] unwrapStringArray(JSObject obj);
|
||||
|
||||
@JSProperty
|
||||
public abstract boolean isMultiEntry();
|
||||
|
||||
@JSProperty
|
||||
public abstract boolean isUnique();
|
||||
|
||||
public abstract IDBCursorRequest openCursor();
|
||||
|
||||
public abstract IDBCursorRequest openCursor(IDBKeyRange range);
|
||||
|
||||
public abstract IDBCursorRequest openKeyCursor();
|
||||
|
||||
public abstract IDBGetRequest get(JSObject key);
|
||||
|
||||
public abstract IDBGetRequest getKey(JSObject key);
|
||||
|
||||
public abstract IDBCountRequest count(JSObject key);
|
||||
|
||||
public abstract IDBCountRequest count();
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
public abstract class IDBKeyRange implements JSObject {
|
||||
@JSProperty
|
||||
public abstract JSObject getLower();
|
||||
|
||||
@JSProperty
|
||||
public abstract JSObject getUpper();
|
||||
|
||||
@JSProperty
|
||||
public abstract boolean isLowerOpen();
|
||||
|
||||
@JSProperty
|
||||
public abstract boolean isUpperOpen();
|
||||
|
||||
@JSBody(params = "value", script = "return IDBKeyRange.only(value);")
|
||||
public static native IDBKeyRange only(JSObject value);
|
||||
|
||||
@JSBody(params = { "lower", "open" }, script = "return IDBKeyRange.lowerBound(lower, open);")
|
||||
public static native IDBKeyRange lowerBound(JSObject lower, boolean open);
|
||||
|
||||
public static IDBKeyRange lowerBound(JSObject lower) {
|
||||
return lowerBound(lower, false);
|
||||
}
|
||||
|
||||
@JSBody(params = { "upper", "open" }, script = "return IDBKeyRange.upperBound(upper, open);")
|
||||
public static native IDBKeyRange upperBound(JSObject upper, boolean open);
|
||||
|
||||
public static IDBKeyRange upperBound(JSObject upper) {
|
||||
return upperBound(upper, false);
|
||||
}
|
||||
|
||||
@JSBody(params = { "lower", "upper", "lowerOpen", "upperOpen" },
|
||||
script = "return IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen);")
|
||||
public static native IDBKeyRange bound(JSObject lower, JSObject upper, boolean lowerOpen, boolean upperOpen);
|
||||
|
||||
public static IDBKeyRange bound(JSObject lower, JSObject upper) {
|
||||
return bound(lower, upper, false, false);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.core.JSString;
|
||||
|
||||
public abstract class IDBObjectStore implements JSObject, IDBCursorSource {
|
||||
@JSProperty
|
||||
public abstract String getName();
|
||||
|
||||
@JSProperty("keyPath")
|
||||
abstract JSObject getKeyPathImpl();
|
||||
|
||||
public final String[] getKeyPath() {
|
||||
JSObject result = getKeyPathImpl();
|
||||
if (JSString.isInstance(result)) {
|
||||
return new String[] { result.<JSString>cast().stringValue() };
|
||||
} else {
|
||||
return unwrapStringArray(result);
|
||||
}
|
||||
}
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return this;")
|
||||
private native String[] unwrapStringArray(JSObject obj);
|
||||
|
||||
@JSProperty
|
||||
public abstract String[] getIndexNames();
|
||||
|
||||
@JSProperty
|
||||
public abstract boolean isAutoIncrement();
|
||||
|
||||
public abstract IDBRequest put(JSObject value, JSObject key);
|
||||
|
||||
public abstract IDBRequest put(JSObject value);
|
||||
|
||||
public abstract IDBRequest add(JSObject value, JSObject key);
|
||||
|
||||
public abstract IDBRequest add(JSObject value);
|
||||
|
||||
public abstract IDBRequest delete(JSObject key);
|
||||
|
||||
public abstract IDBGetRequest get(JSObject key);
|
||||
|
||||
public abstract IDBRequest clear();
|
||||
|
||||
public abstract IDBCursorRequest openCursor();
|
||||
|
||||
public abstract IDBCursorRequest openCursor(IDBKeyRange range);
|
||||
|
||||
public abstract IDBIndex createIndex(String name, String key);
|
||||
|
||||
public abstract IDBIndex createIndex(String name, String[] keys);
|
||||
|
||||
public abstract IDBIndex index(String name);
|
||||
|
||||
public abstract void deleteIndex(String name);
|
||||
|
||||
public abstract IDBCountRequest count();
|
||||
|
||||
public abstract IDBCountRequest count(JSObject key);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
|
||||
public abstract class IDBObjectStoreParameters implements JSObject {
|
||||
@JSBody(script = "return {};")
|
||||
public static native IDBObjectStoreParameters create();
|
||||
|
||||
public final IDBObjectStoreParameters keyPath(String... keys) {
|
||||
setKeyPath(keys);
|
||||
return this;
|
||||
}
|
||||
|
||||
public final IDBObjectStoreParameters autoIncrement(boolean autoIncrement) {
|
||||
setAutoIncrement(autoIncrement);
|
||||
return this;
|
||||
}
|
||||
|
||||
@JSProperty
|
||||
abstract void setKeyPath(String[] keys);
|
||||
|
||||
@JSProperty
|
||||
abstract void setAutoIncrement(boolean autoIncrement);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
|
||||
public interface IDBOpenDBRequest extends IDBRequest {
|
||||
@JSProperty
|
||||
IDBDatabase getResult();
|
||||
|
||||
@JSProperty
|
||||
void setOnBlocked(EventHandler handler);
|
||||
|
||||
@JSProperty("onupgradeneeded")
|
||||
void setOnUpgradeNeeded(EventListener<IDBVersionChangeEvent> listener);
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.dom.events.EventTarget;
|
||||
|
||||
public interface IDBRequest extends EventTarget {
|
||||
String STATE_PENDING = "pending";
|
||||
String STATE_DONE = "done";
|
||||
|
||||
@JSProperty
|
||||
IDBError getError();
|
||||
|
||||
@JSProperty
|
||||
IDBRequestSource getSource();
|
||||
|
||||
@JSProperty
|
||||
IDBTransaction getTransaction();
|
||||
|
||||
@JSProperty
|
||||
String getReadyState();
|
||||
|
||||
@JSProperty("onerror")
|
||||
void setOnError(EventHandler handler);
|
||||
|
||||
@JSProperty("onsuccess")
|
||||
void setOnSuccess(EventHandler handler);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
public interface IDBRequestSource extends JSObject {
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.dom.events.EventTarget;
|
||||
|
||||
public interface IDBTransaction extends JSObject, EventTarget {
|
||||
@JSProperty
|
||||
String getMode();
|
||||
|
||||
@JSProperty
|
||||
IDBDatabase getDb();
|
||||
|
||||
@JSProperty
|
||||
IDBError getError();
|
||||
|
||||
IDBObjectStore objectStore(String name);
|
||||
|
||||
void abort();
|
||||
|
||||
@JSProperty("onabort")
|
||||
void setOnAbort(EventHandler handler);
|
||||
|
||||
@JSProperty("oncomplete")
|
||||
void setOnComplete(EventHandler handler);
|
||||
|
||||
@JSProperty("onerror")
|
||||
void setOnError(EventHandler handler);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.indexeddb;
|
||||
|
||||
import org.teavm.jso.JSProperty;
|
||||
import org.teavm.jso.dom.events.Event;
|
||||
|
||||
public interface IDBVersionChangeEvent extends Event {
|
||||
@JSProperty
|
||||
int getOldVersion();
|
||||
|
||||
@JSProperty
|
||||
int getNewVersion();
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class ArrayBufferInputStream extends InputStream {
|
||||
|
||||
private int position;
|
||||
private int limit;
|
||||
private final ArrayBuffer buffer;
|
||||
private final Uint8Array typed;
|
||||
|
||||
public ArrayBufferInputStream(ArrayBuffer bufferIn) {
|
||||
this(bufferIn, 0, bufferIn.getByteLength());
|
||||
}
|
||||
|
||||
public ArrayBufferInputStream(ArrayBuffer bufferIn, int off, int len) {
|
||||
if(off + len > bufferIn.getByteLength()) {
|
||||
throw new IllegalArgumentException("offset " + off + " and length " + len + " are out of bounds for a "
|
||||
+ bufferIn.getByteLength() + " long arraybuffer");
|
||||
}
|
||||
buffer = bufferIn;
|
||||
typed = Uint8Array.create(bufferIn);
|
||||
position = off;
|
||||
limit = off + len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
if(position >= limit) {
|
||||
return -1;
|
||||
}
|
||||
return typed.get(position++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) {
|
||||
if(off + len > b.length) {
|
||||
throw new ArrayIndexOutOfBoundsException("offset " + off + " and length " + len
|
||||
+ " are out of bounds for a " + b.length + " array");
|
||||
}
|
||||
|
||||
int avail = limit - position;
|
||||
if(len > avail) {
|
||||
len = avail;
|
||||
}
|
||||
|
||||
if(len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < len; ++i) {
|
||||
b[off + i] = (byte)typed.get(position + i);
|
||||
}
|
||||
|
||||
position += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
public long skip(long n) {
|
||||
int avail = limit - position;
|
||||
if(n > avail) {
|
||||
n = avail;
|
||||
}
|
||||
position += (int)n;
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return limit - position;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public ArrayBuffer getBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
import com.jcraft.jzlib.CRC32;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class EPKLoader {
|
||||
|
||||
public static final void loadEPK(ArrayBuffer epkFile, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
loadEPK(epkFile, "", loadedFiles);
|
||||
}
|
||||
|
||||
public static final void loadEPK(ArrayBuffer epkFile, String path, Map<String, byte[]> loadedFiles) throws IOException {
|
||||
int byteLength = epkFile.getByteLength();
|
||||
int l = byteLength - 16;
|
||||
if(l < 1) {
|
||||
throw new IOException("EPK file is incomplete");
|
||||
}
|
||||
|
||||
ArrayBufferInputStream is = new ArrayBufferInputStream(epkFile, 0, byteLength - 8);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
is.read(header);
|
||||
String type = readASCII(header);
|
||||
|
||||
if(!"EAGPKG$$".equals(type)) {
|
||||
throw new IOException("Invalid EPK file type '" + type + "'");
|
||||
}
|
||||
|
||||
Uint8Array readEndCode = Uint8Array.create(epkFile, byteLength - 8, 8);
|
||||
|
||||
byte[] endCode = new byte[] { (byte)':', (byte)':', (byte)':', (byte)'Y',
|
||||
(byte)'E', (byte)'E', (byte)':', (byte)'>' };
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
if(readEndCode.get(i) != endCode[i]) {
|
||||
throw new IOException("EPK file is missing EOF code (:::YEE:>)");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,64 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
|
||||
|
||||
public static final IClientConfigAdapter instance = new TeaVMClientConfigAdapter();
|
||||
|
||||
private String defaultLocale = "en_US";
|
||||
private boolean hideDownDefaultServers = false;
|
||||
private List<DefaultServer> defaultServers = new ArrayList();
|
||||
private String serverToJoin = null;
|
||||
|
||||
void loadJSON(JSONObject eaglercraftOpts) {
|
||||
defaultLocale = eaglercraftOpts.optString("lang", "en_US");
|
||||
serverToJoin = eaglercraftOpts.optString("joinServer", null);
|
||||
JSONArray serversArray = eaglercraftOpts.optJSONArray("servers");
|
||||
if(serversArray != null) {
|
||||
for(int i = 0, l = serversArray.length(); i < l; ++i) {
|
||||
JSONObject serverEntry = serversArray.getJSONObject(i);
|
||||
String serverAddr = serverEntry.optString("addr", null);
|
||||
if(serverAddr != null) {
|
||||
String serverName = serverEntry.optString("name", "Default Server #" + i);
|
||||
defaultServers.add(new DefaultServer(serverName, serverAddr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLocale() {
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DefaultServer> getDefaultServerList() {
|
||||
return defaultServers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerToJoin() {
|
||||
return serverToJoin;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.dom.events.Event;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import org.teavm.jso.dom.events.MessageEvent;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Int8Array;
|
||||
import org.teavm.jso.websocket.WebSocket;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumServerRateLimit;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.QueryResponse;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class TeaVMServerQuery implements IServerQuery {
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("WebSocketQuery");
|
||||
|
||||
private final List<QueryResponse> queryResponses = new LinkedList();
|
||||
private final List<byte[]> queryResponsesBytes = new LinkedList();
|
||||
|
||||
protected final String uri;
|
||||
protected final String accept;
|
||||
protected final WebSocket sock;
|
||||
protected boolean open = true;
|
||||
protected boolean alive = false;
|
||||
protected long pingStart = -1l;
|
||||
protected long pingTimer = -1l;
|
||||
private EnumServerRateLimit rateLimit = EnumServerRateLimit.OK;
|
||||
|
||||
public TeaVMServerQuery(String uri, String accept) {
|
||||
this.uri = uri;
|
||||
this.accept = accept;
|
||||
this.sock = WebSocket.create(uri);
|
||||
initHandlers();
|
||||
}
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return typeof obj === \"string\";")
|
||||
private static native boolean isString(JSObject obj);
|
||||
|
||||
protected void initHandlers() {
|
||||
sock.setBinaryType("arraybuffer");
|
||||
TeaVMUtils.addEventListener(sock, "open", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
sock.send("Accept: " + accept);
|
||||
}
|
||||
});
|
||||
TeaVMUtils.addEventListener(sock, "close", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
open = false;
|
||||
}
|
||||
});
|
||||
TeaVMUtils.addEventListener(sock, "message", new EventListener<MessageEvent>() {
|
||||
@Override
|
||||
public void handleEvent(MessageEvent evt) {
|
||||
alive = true;
|
||||
if(pingTimer == -1) {
|
||||
pingTimer = System.currentTimeMillis() - pingStart;
|
||||
if(pingTimer < 1) {
|
||||
pingTimer = 1;
|
||||
}
|
||||
}
|
||||
if(isString(evt.getData())) {
|
||||
String str = evt.getDataAsString();
|
||||
if(str.equalsIgnoreCase("BLOCKED")) {
|
||||
logger.error("Reached full IP ratelimit for {}!", uri);
|
||||
rateLimit = EnumServerRateLimit.BLOCKED;
|
||||
return;
|
||||
}
|
||||
if(str.equalsIgnoreCase("LOCKED")) {
|
||||
logger.error("Reached full IP ratelimit lockout for {}!", uri);
|
||||
rateLimit = EnumServerRateLimit.LOCKED_OUT;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JSONObject obj = new JSONObject(str);
|
||||
if("blocked".equalsIgnoreCase(obj.optString("type", null))) {
|
||||
logger.error("Reached query ratelimit for {}!", uri);
|
||||
rateLimit = EnumServerRateLimit.BLOCKED;
|
||||
}else if("locked".equalsIgnoreCase(obj.optString("type", null))) {
|
||||
logger.error("Reached query ratelimit lockout for {}!", uri);
|
||||
rateLimit = EnumServerRateLimit.LOCKED_OUT;
|
||||
}else {
|
||||
QueryResponse response = new QueryResponse(obj, pingTimer);
|
||||
synchronized(queryResponses) {
|
||||
queryResponses.add(response);
|
||||
}
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
logger.error("Exception thrown parsing websocket query response from \"" + uri + "\"!");
|
||||
logger.error(t);
|
||||
}
|
||||
}else {
|
||||
synchronized(queryResponsesBytes) {
|
||||
Int8Array packetBytes = Int8Array.create(evt.getDataAsArray());
|
||||
byte[] data = new byte[packetBytes.getLength()];
|
||||
for(int i = 0; i < data.length; ++i) {
|
||||
data[i] = packetBytes.get(i);
|
||||
}
|
||||
queryResponsesBytes.add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
TeaVMUtils.addEventListener(sock, "error", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
sock.close();
|
||||
open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String str) {
|
||||
if(open) {
|
||||
sock.send(str);
|
||||
}
|
||||
}
|
||||
|
||||
@JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);")
|
||||
private static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer);
|
||||
|
||||
@Override
|
||||
public void send(byte[] bytes) {
|
||||
if(open) {
|
||||
Int8Array arr = Int8Array.create(bytes.length);
|
||||
arr.set(bytes, 0);
|
||||
nativeBinarySend(sock, arr.getBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int responsesAvailable() {
|
||||
synchronized(queryResponses) {
|
||||
return queryResponses.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResponse getResponse() {
|
||||
synchronized(queryResponses) {
|
||||
if(queryResponses.size() > 0) {
|
||||
return queryResponses.remove(0);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int binaryResponsesAvailable() {
|
||||
synchronized(queryResponsesBytes) {
|
||||
return queryResponsesBytes.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBinaryResponse() {
|
||||
synchronized(queryResponsesBytes) {
|
||||
if(queryResponsesBytes.size() > 0) {
|
||||
return queryResponsesBytes.remove(0);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryReadyState readyState() {
|
||||
return open ? (alive ? QueryReadyState.OPEN : QueryReadyState.CONNECTING)
|
||||
: (alive ? QueryReadyState.CLOSED : QueryReadyState.FAILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(open) {
|
||||
open = false;
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumServerRateLimit getRateLimit() {
|
||||
return rateLimit;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Int8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class TeaVMUtils {
|
||||
|
||||
@JSBody(params = { "url" }, script = "URL.revokeObjectURL(url);")
|
||||
public static native void freeDataURL(String url);
|
||||
|
||||
@JSBody(params = { "buf", "mime" }, script = "return URL.createObjectURL(new Blob([buf], {type: mime}));")
|
||||
public static native String getDataURL(ArrayBuffer buf, String mime);
|
||||
|
||||
@JSBody(params = { "obj", "name", "handler" }, script = "obj.addEventListener(name, handler);")
|
||||
public static native void addEventListener(JSObject obj, String name, JSObject handler);
|
||||
|
||||
public static final byte[] arrayBufferToBytes(ArrayBuffer buf) {
|
||||
if(buf == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Int8Array arr = Int8Array.create(buf);
|
||||
byte[] ret = new byte[arr.getByteLength()];
|
||||
for(int i = 0; i < ret.length; ++i) {
|
||||
ret[i] = arr.get(i);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import org.teavm.jso.webgl.WebGLRenderingContext;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public interface WebGL2RenderingContext extends WebGLRenderingContext {
|
||||
|
||||
int TEXTURE_MAX_LEVEL = 0x0000813D;
|
||||
int TEXTURE_MAX_ANISOTROPY_EXT = 0x000084FE;
|
||||
int UNSIGNED_INT_24_8 = 0x000084FA;
|
||||
int ANY_SAMPLES_PASSED = 0x00008D6A;
|
||||
int QUERY_RESULT = 0x00008866;
|
||||
int QUERY_RESULT_AVAILABLE = 0x00008867;
|
||||
int DEPTH24_STENCIL8 = 0x000088F0;
|
||||
int DEPTH_COMPONENT32F = 0x00008CAC;
|
||||
int READ_FRAMEBUFFER = 0x00008CA8;
|
||||
int DRAW_FRAMEBUFFER = 0x00008CA9;
|
||||
int RGB8 = 0x00008051;
|
||||
int RGBA8 = 0x00008058;
|
||||
int R8 = 0x00008229;
|
||||
int RED = 0x00001903;
|
||||
|
||||
WebGLQuery createQuery();
|
||||
|
||||
void beginQuery(int p1, WebGLQuery obj);
|
||||
|
||||
void endQuery(int p1);
|
||||
|
||||
void deleteQuery(WebGLQuery obj);
|
||||
|
||||
int getQueryParameter(WebGLQuery obj, int p2);
|
||||
|
||||
WebGLVertexArray createVertexArray();
|
||||
|
||||
void deleteVertexArray(WebGLVertexArray obj);
|
||||
|
||||
void bindVertexArray(WebGLVertexArray obj);
|
||||
|
||||
void renderbufferStorageMultisample(int p1, int p2, int p3, int p4, int p5);
|
||||
|
||||
void blitFramebuffer(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10);
|
||||
|
||||
void drawBuffers(int[] p1);
|
||||
|
||||
void readBuffer(int p1);
|
||||
|
||||
void vertexAttribDivisor(int p1, int p2);
|
||||
|
||||
void drawArraysInstanced(int p1, int p2, int p3, int p4);
|
||||
|
||||
void drawElementsInstanced(int p1, int p2, int p3, int p4, int p5);
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public interface WebGLQuery extends JSObject {
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
|
||||
import org.teavm.jso.JSObject;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public interface WebGLVertexArray extends JSObject {
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
|
||||
public class BooleanResult {
|
||||
|
||||
public static final BooleanResult TRUE = new BooleanResult(true);
|
||||
public static final BooleanResult FALSE = new BooleanResult(false);
|
||||
|
||||
public final boolean bool;
|
||||
|
||||
private BooleanResult(boolean b) {
|
||||
bool = b;
|
||||
}
|
||||
|
||||
public static BooleanResult _new(boolean b) {
|
||||
return b ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraft.client.resources.AbstractResourcePack;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
|
||||
public class FolderResourcePack extends AbstractResourcePack {
|
||||
private final String prefix;
|
||||
|
||||
public FolderResourcePack(String resourcePackFileIn, String prefix) {
|
||||
super(resourcePackFileIn);
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
protected InputStream getInputStreamByName(String name) {
|
||||
return SYS.VFS.getFile(prefix + this.resourcePackFile + "/" + name).getInputStream();
|
||||
}
|
||||
|
||||
protected boolean hasResourceName(String name) {
|
||||
return SYS.VFS.fileExists(prefix + this.resourcePackFile + "/" + name);
|
||||
}
|
||||
|
||||
public Set<String> getResourceDomains() {
|
||||
Set<String> set = Sets.<String>newHashSet();
|
||||
String pfx = prefix + this.resourcePackFile + "/assets/";
|
||||
List<String> files = SYS.VFS.listFiles(pfx);
|
||||
|
||||
for (String file : files) {
|
||||
String s = file.substring(pfx.length());
|
||||
int ind = s.indexOf('/');
|
||||
if (ind != -1) s = s.substring(0, ind);
|
||||
if (!s.equals(s.toLowerCase())) {
|
||||
this.logNameNotLowercase(s);
|
||||
} else {
|
||||
set.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.teavm.ArrayBufferInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs.VirtualFilesystem.VFSHandle;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
|
||||
public class SYS {
|
||||
|
||||
public static final VirtualFilesystem VFS;
|
||||
|
||||
static {
|
||||
VFSHandle vh = VirtualFilesystem.openVFS("_net_lax1dude_eaglercraft_v1_8_VirtualFilesystem_");
|
||||
|
||||
if(vh.vfs == null) {
|
||||
System.err.println("Could not init filesystem!");
|
||||
}
|
||||
|
||||
VFS = vh.vfs;
|
||||
|
||||
List<String> srp = getResourcePackNames(true);
|
||||
for (String name : srp) {
|
||||
if (System.currentTimeMillis() - Long.parseLong(name.substring(name.lastIndexOf('_') + 1)) >= 604800000L) {
|
||||
deleteResourcePack(name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final void loadRemoteResourcePack(String url, String hash, Consumer<String> cb, Consumer<Runnable> ast, Runnable loading) {
|
||||
if (!hash.matches("^[a-f0-9]{40}$")) {
|
||||
cb.accept(null);
|
||||
return;
|
||||
}
|
||||
List<String> srpPre = getResourcePackNames(true);
|
||||
String alreadyHere = srpPre.stream().filter(s -> s.startsWith(hash + "_")).findFirst().orElse(null);
|
||||
if (alreadyHere != null) {
|
||||
cb.accept(alreadyHere);
|
||||
return;
|
||||
}
|
||||
PlatformRuntime.downloadRemoteURI(url, ab -> {
|
||||
ast.accept(() -> {
|
||||
if (ab == null) {
|
||||
cb.accept(null);
|
||||
return;
|
||||
}
|
||||
List<String> srp = getResourcePackNames(true);
|
||||
// delete old server resource packs - todo: test
|
||||
if (srp.size() > 5) {
|
||||
srp.sort(Comparator.comparingLong(val -> Long.parseLong(val.substring(val.lastIndexOf('_') + 1))));
|
||||
for (int i = 0; i < srp.size() - 5; i++) {
|
||||
deleteResourcePack(srp.get(i), true);
|
||||
}
|
||||
}
|
||||
String packName = hash + "_" + System.currentTimeMillis();
|
||||
loading.run();
|
||||
boolean success = loadResourcePack(packName + ".zip", new ArrayBufferInputStream(ab), hash);
|
||||
if (success) {
|
||||
cb.accept(packName);
|
||||
return;
|
||||
}
|
||||
cb.accept(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static final boolean loadResourcePack(String name, InputStream is, String hash) {
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
|
||||
bis.mark(Integer.MAX_VALUE);
|
||||
|
||||
if (hash != null) {
|
||||
try {
|
||||
SHA1Digest digest = new SHA1Digest();
|
||||
byte[] buffer = new byte[16000];
|
||||
int read = 0;
|
||||
|
||||
while ((read = bis.read(buffer)) > 0) {
|
||||
digest.update(buffer, 0, read);
|
||||
}
|
||||
|
||||
byte[] sha1sum = new byte[20];
|
||||
digest.doFinal(sha1sum, 0);
|
||||
bis.reset();
|
||||
if (!hash.equals((new BigInteger(1, sha1sum)).toString(16))) {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String packName = name.substring(0, name.lastIndexOf('.')).replace('/', '_');
|
||||
try {
|
||||
int prefixLen = Integer.MAX_VALUE;
|
||||
ZipInputStream ziss = new ZipInputStream(bis);
|
||||
ZipEntry zipEntryy;
|
||||
while ((zipEntryy = ziss.getNextEntry()) != null) {
|
||||
String zn;
|
||||
if (!zipEntryy.isDirectory() && ((zn = zipEntryy.getName()).equals("pack.mcmeta") || zn.endsWith("/pack.mcmeta"))) {
|
||||
int currPrefixLen = zn.length() - 11;
|
||||
if (prefixLen > currPrefixLen) {
|
||||
prefixLen = currPrefixLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prefixLen == Integer.MAX_VALUE) {
|
||||
prefixLen = 0;
|
||||
}
|
||||
|
||||
bis.reset();
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(bis);
|
||||
byte[] bb = new byte[16000];
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = zis.getNextEntry()) != null) {
|
||||
if (zipEntry.isDirectory()) continue;
|
||||
if (zipEntry.getName().length() <= prefixLen) continue;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int len;
|
||||
while ((len = zis.read(bb)) != -1) {
|
||||
baos.write(bb, 0, len);
|
||||
}
|
||||
baos.close();
|
||||
SYS.VFS.getFile((hash == null ? "resourcepacks/" : "srp/") + packName + "/" + zipEntry.getName().substring(prefixLen)).setAllBytes(baos.toByteArray());
|
||||
}
|
||||
zis.closeEntry();
|
||||
zis.close();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final List<String> getResourcePackNames() {
|
||||
return getResourcePackNames(false);
|
||||
}
|
||||
|
||||
private static final List<String> getResourcePackNames(boolean srp) {
|
||||
List<String> res = new ArrayList<>();
|
||||
List<String> resourcePackFiles = SYS.VFS.listFiles(srp ? "srp/" : "resourcepacks/");
|
||||
for (String path : resourcePackFiles) {
|
||||
String trimmed = path.substring(srp ? 4 : 14);
|
||||
trimmed = trimmed.substring(0, trimmed.indexOf('/'));
|
||||
boolean hasIt = false;
|
||||
for (String alreadyHas : res) {
|
||||
if (trimmed.equals(alreadyHas)) {
|
||||
hasIt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasIt) continue;
|
||||
res.add(trimmed);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static final void deleteResourcePack(String packName) {
|
||||
deleteResourcePack(packName, false);
|
||||
}
|
||||
|
||||
private static final void deleteResourcePack(String packName, boolean srp) {
|
||||
SYS.VFS.deleteFiles((srp ? "srp/" : "resourcepacks/") + packName);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
|
||||
public interface VFSIterator {
|
||||
|
||||
public static class BreakLoop extends RuntimeException {
|
||||
public BreakLoop() {
|
||||
super("iterator loop break request");
|
||||
}
|
||||
}
|
||||
|
||||
public default void end() {
|
||||
throw new BreakLoop();
|
||||
}
|
||||
|
||||
public void next(VIteratorFile entry);
|
||||
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
|
||||
public class VFile {
|
||||
|
||||
public static final String pathSeperator = "/";
|
||||
public static final String[] altPathSeperator = new String[] { "\\" };
|
||||
|
||||
public static String normalizePath(String p) {
|
||||
for(int i = 0; i < altPathSeperator.length; ++i) {
|
||||
p = p.replace(altPathSeperator[i], pathSeperator);
|
||||
}
|
||||
if(p.startsWith(pathSeperator)) {
|
||||
p = p.substring(1);
|
||||
}
|
||||
if(p.endsWith(pathSeperator)) {
|
||||
p = p.substring(0, p.length() - pathSeperator.length());
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public static String[] splitPath(String p) {
|
||||
String[] pth = normalizePath(p).split(pathSeperator);
|
||||
for(int i = 0; i < pth.length; ++i) {
|
||||
pth[i] = pth[i].trim();
|
||||
}
|
||||
return pth;
|
||||
}
|
||||
|
||||
protected String path;
|
||||
|
||||
public static String createPath(Object... p) {
|
||||
ArrayList<String> r = new ArrayList();
|
||||
for(int i = 0; i < p.length; ++i) {
|
||||
if(p[i] == null) {
|
||||
continue;
|
||||
}
|
||||
String gg = p[i].toString();
|
||||
if(gg == null) {
|
||||
continue;
|
||||
}
|
||||
String[] parts = splitPath(gg);
|
||||
for(int j = 0; j < parts.length; ++j) {
|
||||
if(parts[j] == null || parts[j].equals(".")) {
|
||||
continue;
|
||||
}else if(parts[j].equals("..") && r.size() > 0) {
|
||||
int k = r.size() - 1;
|
||||
if(!r.get(k).equals("..")) {
|
||||
r.remove(k);
|
||||
}else {
|
||||
r.add("..");
|
||||
}
|
||||
}else {
|
||||
r.add(parts[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(r.size() > 0) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
for(int i = 0; i < r.size(); ++i) {
|
||||
if(i > 0) {
|
||||
s.append(pathSeperator);
|
||||
}
|
||||
s.append(r.get(i));
|
||||
}
|
||||
return s.toString();
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public VFile(Object... p) {
|
||||
this.path = createPath(p);
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return isRelative() ? null : SYS.VFS.getFile(path).getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return isRelative() ? null : SYS.VFS.getFile(path).getOutputStream();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public boolean isRelative() {
|
||||
return path == null || path.contains("..");
|
||||
}
|
||||
|
||||
public boolean canRead() {
|
||||
return !isRelative() && SYS.VFS.fileExists(path);
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path.equals("unnamed") ? null : path;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if(path == null) {
|
||||
return null;
|
||||
}
|
||||
int i = path.indexOf(pathSeperator);
|
||||
return i == -1 ? path : path.substring(i + 1);
|
||||
}
|
||||
|
||||
public boolean canWrite() {
|
||||
return !isRelative();
|
||||
}
|
||||
|
||||
public String getParent() {
|
||||
if(path == null) {
|
||||
return null;
|
||||
}
|
||||
int i = path.indexOf(pathSeperator);
|
||||
return i == -1 ? ".." : path.substring(0, i);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return path == null ? 0 : path.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return path != null && o != null && (o instanceof VFile) && path.equals(((VFile)o).path);
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return !isRelative() && SYS.VFS.fileExists(path);
|
||||
}
|
||||
|
||||
public boolean delete() {
|
||||
return !isRelative() && SYS.VFS.deleteFile(path);
|
||||
}
|
||||
|
||||
public boolean renameTo(String p, boolean copy) {
|
||||
if(!isRelative() && SYS.VFS.renameFile(path, p, copy)) {
|
||||
path = p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return isRelative() ? -1 : SYS.VFS.getFile(path).getSize();
|
||||
}
|
||||
|
||||
public void getBytes(int fileOffset, byte[] array, int offset, int length) {
|
||||
if(isRelative()) {
|
||||
throw new ArrayIndexOutOfBoundsException("File is relative");
|
||||
}
|
||||
SYS.VFS.getFile(path).getBytes(fileOffset, array, offset, length);
|
||||
}
|
||||
|
||||
public void setCacheEnabled() {
|
||||
if(isRelative()) {
|
||||
throw new RuntimeException("File is relative");
|
||||
}
|
||||
SYS.VFS.getFile(path).setCacheEnabled();
|
||||
}
|
||||
|
||||
public byte[] getAllBytes() {
|
||||
if(isRelative()) {
|
||||
return null;
|
||||
}
|
||||
return SYS.VFS.getFile(path).getAllBytes();
|
||||
}
|
||||
|
||||
public String getAllChars() {
|
||||
if(isRelative()) {
|
||||
return null;
|
||||
}
|
||||
return SYS.VFS.getFile(path).getAllChars();
|
||||
}
|
||||
|
||||
public String[] getAllLines() {
|
||||
if(isRelative()) {
|
||||
return null;
|
||||
}
|
||||
return SYS.VFS.getFile(path).getAllLines();
|
||||
}
|
||||
|
||||
public byte[] getAllBytes(boolean copy) {
|
||||
if(isRelative()) {
|
||||
return null;
|
||||
}
|
||||
return SYS.VFS.getFile(path).getAllBytes(copy);
|
||||
}
|
||||
|
||||
public boolean setAllChars(String bytes) {
|
||||
if(isRelative()) {
|
||||
return false;
|
||||
}
|
||||
return SYS.VFS.getFile(path).setAllChars(bytes);
|
||||
}
|
||||
|
||||
public boolean setAllBytes(byte[] bytes) {
|
||||
if(isRelative()) {
|
||||
return false;
|
||||
}
|
||||
return SYS.VFS.getFile(path).setAllBytes(bytes);
|
||||
}
|
||||
|
||||
public boolean setAllBytes(byte[] bytes, boolean copy) {
|
||||
if(isRelative()) {
|
||||
return false;
|
||||
}
|
||||
return SYS.VFS.getFile(path).setAllBytes(bytes, copy);
|
||||
}
|
||||
|
||||
public List<String> list() {
|
||||
if(isRelative()) {
|
||||
return Arrays.asList(path);
|
||||
}
|
||||
return SYS.VFS.listFiles(path);
|
||||
}
|
||||
|
||||
public int deleteAll() {
|
||||
return isRelative() ? 0 : SYS.VFS.deleteFiles(path);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,303 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.dom.events.Event;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBCursor;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBRequest;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Do not use an instance of this class outside of the VFSIterator.next() method
|
||||
*/
|
||||
public class VIteratorFile extends VFile {
|
||||
|
||||
static final VIteratorFile instance = new VIteratorFile();
|
||||
|
||||
private VIteratorFile() {
|
||||
super("");
|
||||
this.idx = -1;
|
||||
this.cur = null;
|
||||
this.vfs = null;
|
||||
}
|
||||
|
||||
private static class VirtualIteratorOutputStream extends ByteArrayOutputStream {
|
||||
|
||||
private final VIteratorFile itr;
|
||||
|
||||
protected VirtualIteratorOutputStream(VIteratorFile itr) {
|
||||
this.itr = itr;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if(!itr.setAllBytes(super.toByteArray(), false)) {
|
||||
throw new IOException("Could not close stream and write to \"" + itr.path + "\" on VFS \"" + itr.vfs.database + "\" (the file was probably deleted)");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int idx;
|
||||
private IDBCursor cur;
|
||||
private VirtualFilesystem vfs;
|
||||
private boolean wasDeleted;
|
||||
|
||||
@JSBody(params = { "k" }, script = "return ((typeof k) === \"string\") ? k : (((typeof k) === \"undefined\") ? null : (((typeof k[0]) === \"string\") ? k[0] : null));")
|
||||
private static native String readKey(JSObject k);
|
||||
|
||||
static VIteratorFile create(int idx, VirtualFilesystem vfs, IDBCursor cur) {
|
||||
String k = readKey(cur.getKey());
|
||||
if(k == null) {
|
||||
return null;
|
||||
}
|
||||
instance.update(idx, k, vfs, cur);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public VFile makeVFile() {
|
||||
return new VFile(path);
|
||||
}
|
||||
|
||||
private void update(int idx, String path, VirtualFilesystem vfs, IDBCursor cur) {
|
||||
this.idx = idx;
|
||||
this.path = path;
|
||||
this.vfs = vfs;
|
||||
this.cur = cur;
|
||||
this.wasDeleted = false;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return !wasDeleted ? new ByteArrayInputStream(getAllBytes()) : null;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return !wasDeleted ? new VirtualIteratorOutputStream(this) : null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public boolean isRelative() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canRead() {
|
||||
return !wasDeleted;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if(path == null) {
|
||||
return null;
|
||||
}
|
||||
int i = path.indexOf(pathSeperator);
|
||||
return i == -1 ? path : path.substring(i + 1);
|
||||
}
|
||||
|
||||
public boolean canWrite() {
|
||||
return !wasDeleted;
|
||||
}
|
||||
|
||||
public String getParent() {
|
||||
if(path == null) {
|
||||
return null;
|
||||
}
|
||||
int i = path.indexOf(pathSeperator);
|
||||
return i == -1 ? ".." : path.substring(0, i);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return path == null ? 0 : path.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return path != null && o != null && (o instanceof VFile) && path.equals(((VFile)o).path);
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return !wasDeleted;
|
||||
}
|
||||
|
||||
public boolean delete() {
|
||||
return wasDeleted = AsyncHandlers.awaitRequest(cur.delete()).bool;
|
||||
}
|
||||
|
||||
public boolean renameTo(String p) {
|
||||
byte[] data = getAllBytes();
|
||||
String op = path;
|
||||
path = p;
|
||||
if(!setAllBytes(data)) {
|
||||
path = op;
|
||||
return false;
|
||||
}
|
||||
path = op;
|
||||
if(!delete()) {
|
||||
return false;
|
||||
}
|
||||
path = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
JSObject obj = cur.getValue();
|
||||
|
||||
if(obj == null) {
|
||||
throw new RuntimeException("Value of entry is missing");
|
||||
}
|
||||
|
||||
ArrayBuffer arr = readRow(obj);
|
||||
|
||||
if(arr == null) {
|
||||
throw new RuntimeException("Value of the fucking value of the entry is missing");
|
||||
}
|
||||
|
||||
return arr.getByteLength();
|
||||
}
|
||||
|
||||
public void getBytes(int fileOffset, byte[] array, int offset, int length) {
|
||||
JSObject obj = cur.getValue();
|
||||
|
||||
if(obj == null) {
|
||||
throw new ArrayIndexOutOfBoundsException("Value of entry is missing");
|
||||
}
|
||||
|
||||
ArrayBuffer arr = readRow(obj);
|
||||
|
||||
if(arr == null) {
|
||||
throw new ArrayIndexOutOfBoundsException("Value of the fucking value of the entry is missing");
|
||||
}
|
||||
|
||||
Uint8Array a = Uint8Array.create(arr);
|
||||
|
||||
if(a.getLength() < fileOffset + length) {
|
||||
throw new ArrayIndexOutOfBoundsException("file '" + path + "' size was "+a.getLength()+" but user tried to read index "+(fileOffset + length - 1));
|
||||
}
|
||||
|
||||
for(int i = 0; i < length; ++i) {
|
||||
array[i + offset] = (byte)a.get(i + fileOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCacheEnabled() {
|
||||
// no
|
||||
}
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return (typeof obj === 'undefined') ? null : ((typeof obj.data === 'undefined') ? null : obj.data);")
|
||||
private static native ArrayBuffer readRow(JSObject obj);
|
||||
|
||||
public byte[] getAllBytes() {
|
||||
JSObject obj = cur.getValue();
|
||||
|
||||
if(obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayBuffer arr = readRow(obj);
|
||||
|
||||
if(arr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Uint8Array a = Uint8Array.create(arr);
|
||||
int ii = a.getByteLength();
|
||||
|
||||
byte[] array = new byte[ii];
|
||||
for(int i = 0; i < ii; ++i) {
|
||||
array[i] = (byte)a.get(i);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public String getAllChars() {
|
||||
return VirtualFilesystem.utf8(getAllBytes());
|
||||
}
|
||||
|
||||
public String[] getAllLines() {
|
||||
return VirtualFilesystem.lines(VirtualFilesystem.utf8(getAllBytes()));
|
||||
}
|
||||
|
||||
public byte[] getAllBytes(boolean copy) {
|
||||
return getAllBytes();
|
||||
}
|
||||
|
||||
public boolean setAllChars(String bytes) {
|
||||
return setAllBytes(VirtualFilesystem.utf8(bytes));
|
||||
}
|
||||
|
||||
public List<String> list() {
|
||||
throw new RuntimeException("Cannot perform list all in VFS callback");
|
||||
}
|
||||
|
||||
public int deleteAll() {
|
||||
throw new RuntimeException("Cannot perform delete all in VFS callback");
|
||||
}
|
||||
|
||||
@JSBody(params = { "pat", "dat" }, script = "return { path: pat, data: dat };")
|
||||
private static native JSObject writeRow(String name, ArrayBuffer data);
|
||||
|
||||
public boolean setAllBytes(byte[] bytes) {
|
||||
ArrayBuffer a = ArrayBuffer.create(bytes.length);
|
||||
Uint8Array ar = Uint8Array.create(a);
|
||||
ar.set(bytes);
|
||||
JSObject obj = writeRow(path, a);
|
||||
BooleanResult r = AsyncHandlers.awaitRequest(cur.update(obj));
|
||||
return r.bool;
|
||||
}
|
||||
|
||||
public boolean setAllBytes(byte[] bytes, boolean copy) {
|
||||
return setAllBytes(bytes);
|
||||
}
|
||||
|
||||
public static class AsyncHandlers {
|
||||
|
||||
@Async
|
||||
public static native BooleanResult awaitRequest(IDBRequest r);
|
||||
|
||||
private static void awaitRequest(IDBRequest r, final AsyncCallback<BooleanResult> cb) {
|
||||
r.addEventListener("success", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
cb.complete(BooleanResult._new(true));
|
||||
}
|
||||
});
|
||||
r.addEventListener("error", new EventListener<Event>() {
|
||||
@Override
|
||||
public void handleEvent(Event evt) {
|
||||
cb.complete(BooleanResult._new(false));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,708 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.AsyncCallback;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.dom.events.EventListener;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.EventHandler;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBCountRequest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBCursor;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBCursorRequest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBDatabase;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBFactory;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBGetRequest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBObjectStoreParameters;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBOpenDBRequest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBRequest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBTransaction;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.indexeddb.IDBVersionChangeEvent;
|
||||
import org.teavm.jso.typedarrays.ArrayBuffer;
|
||||
import org.teavm.jso.typedarrays.Uint8Array;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
|
||||
public class VirtualFilesystem {
|
||||
|
||||
protected static class VirtualOutputStream extends ByteArrayOutputStream {
|
||||
private final VFSFile file;
|
||||
|
||||
protected VirtualOutputStream(VFSFile file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if(!file.setAllBytes(super.toByteArray(), false)) {
|
||||
throw new IOException("Could not close stream and write to \"" + file.filePath + "\" on VFS \"" + file.virtualFilesystem.database + "\" (the file was probably deleted)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class VFSFile {
|
||||
|
||||
public final VirtualFilesystem virtualFilesystem;
|
||||
protected boolean cacheEnabled;
|
||||
protected String filePath;
|
||||
protected int fileSize = -1;
|
||||
protected boolean hasBeenDeleted = false;
|
||||
protected boolean hasBeenAccessed = false;
|
||||
protected boolean exists = false;
|
||||
|
||||
protected byte[] cache = null;
|
||||
protected long cacheHit;
|
||||
|
||||
protected VFSFile(VirtualFilesystem vfs, String filePath, boolean cacheEnabled) {
|
||||
this.virtualFilesystem = vfs;
|
||||
this.filePath = filePath;
|
||||
this.cacheHit = System.currentTimeMillis();
|
||||
if(cacheEnabled) {
|
||||
setCacheEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof VFSFile) && ((VFSFile)o).filePath.equals(filePath);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return filePath.hashCode();
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
cacheHit = System.currentTimeMillis();
|
||||
if(fileSize < 0) {
|
||||
if(cacheEnabled) {
|
||||
byte[] b = getAllBytes(false);
|
||||
if(b != null) {
|
||||
fileSize = b.length;
|
||||
}
|
||||
}else {
|
||||
ArrayBuffer dat = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||
if(dat != null) {
|
||||
fileSize = dat.getByteLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
byte[] dat = getAllBytes(false);
|
||||
if(dat == null) {
|
||||
return null;
|
||||
}
|
||||
return new EaglerInputStream(dat);
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return new VirtualOutputStream(this);
|
||||
}
|
||||
|
||||
public void getBytes(int fileOffset, byte[] array, int offset, int length) {
|
||||
if(hasBeenDeleted) {
|
||||
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' has been deleted");
|
||||
}else if(hasBeenAccessed && !exists) {
|
||||
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' does not exist");
|
||||
}
|
||||
cacheHit = System.currentTimeMillis();
|
||||
if(cacheEnabled && cache != null) {
|
||||
System.arraycopy(cache, fileOffset, array, offset, length);
|
||||
}else {
|
||||
ArrayBuffer aa = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||
hasBeenAccessed = true;
|
||||
if(aa != null) {
|
||||
exists = true;
|
||||
}else {
|
||||
exists = false;
|
||||
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' does not exist");
|
||||
}
|
||||
Uint8Array a = Uint8Array.create(aa);
|
||||
this.fileSize = a.getByteLength();
|
||||
if(cacheEnabled) {
|
||||
cache = new byte[fileSize];
|
||||
for(int i = 0; i < fileSize; ++i) {
|
||||
cache[i] = (byte)a.get(i);
|
||||
}
|
||||
}
|
||||
if(a.getLength() < fileOffset + length) {
|
||||
throw new ArrayIndexOutOfBoundsException("file '" + filePath + "' size was "+a.getLength()+" but user tried to read index "+(fileOffset + length - 1));
|
||||
}
|
||||
for(int i = 0; i < length; ++i) {
|
||||
array[i + offset] = (byte)a.get(i + fileOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCacheEnabled() {
|
||||
if(!cacheEnabled && !hasBeenDeleted && !(hasBeenAccessed && !exists)) {
|
||||
cacheHit = System.currentTimeMillis();
|
||||
cache = getAllBytes(false);
|
||||
cacheEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getAllBytes() {
|
||||
return getAllBytes(false);
|
||||
}
|
||||
|
||||
public String getAllChars() {
|
||||
return utf8(getAllBytes(false));
|
||||
}
|
||||
|
||||
public String[] getAllLines() {
|
||||
return lines(getAllChars());
|
||||
}
|
||||
|
||||
public byte[] getAllBytes(boolean copy) {
|
||||
if(hasBeenDeleted || (hasBeenAccessed && !exists)) {
|
||||
return null;
|
||||
}
|
||||
cacheHit = System.currentTimeMillis();
|
||||
if(cacheEnabled && cache != null) {
|
||||
byte[] b = cache;
|
||||
if(copy) {
|
||||
b = new byte[cache.length];
|
||||
System.arraycopy(cache, 0, b, 0, cache.length);
|
||||
}
|
||||
return b;
|
||||
}else {
|
||||
hasBeenAccessed = true;
|
||||
ArrayBuffer b = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||
if(b != null) {
|
||||
exists = true;
|
||||
}else {
|
||||
exists = false;
|
||||
return null;
|
||||
}
|
||||
Uint8Array a = Uint8Array.create(b);
|
||||
this.fileSize = a.getByteLength();
|
||||
byte[] array = new byte[fileSize];
|
||||
for(int i = 0; i < a.getByteLength(); ++i) {
|
||||
array[i] = (byte)a.get(i);
|
||||
}
|
||||
if(cacheEnabled) {
|
||||
if(copy) {
|
||||
cache = new byte[fileSize];
|
||||
System.arraycopy(b, 0, cache, 0, cache.length);
|
||||
}else {
|
||||
cache = array;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setAllChars(String bytes) {
|
||||
return setAllBytes(utf8(bytes), true);
|
||||
}
|
||||
|
||||
public boolean setAllBytes(byte[] bytes) {
|
||||
return setAllBytes(bytes, true);
|
||||
}
|
||||
|
||||
public boolean setAllBytes(byte[] bytes, boolean copy) {
|
||||
if(hasBeenDeleted || bytes == null) {
|
||||
return false;
|
||||
}
|
||||
cacheHit = System.currentTimeMillis();
|
||||
this.fileSize = bytes.length;
|
||||
if(cacheEnabled) {
|
||||
byte[] copz = bytes;
|
||||
if(copy) {
|
||||
copz = new byte[bytes.length];
|
||||
System.arraycopy(bytes, 0, copz, 0, bytes.length);
|
||||
}
|
||||
cache = copz;
|
||||
return sync();
|
||||
}else {
|
||||
ArrayBuffer a = ArrayBuffer.create(bytes.length);
|
||||
Uint8Array ar = Uint8Array.create(a);
|
||||
ar.set(bytes);
|
||||
boolean s = AsyncHandlers.writeWholeFile(virtualFilesystem.indexeddb, filePath, a).bool;
|
||||
hasBeenAccessed = true;
|
||||
exists = exists || s;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean sync() {
|
||||
if(cacheEnabled && cache != null && !hasBeenDeleted) {
|
||||
cacheHit = System.currentTimeMillis();
|
||||
ArrayBuffer a = ArrayBuffer.create(cache.length);
|
||||
Uint8Array ar = Uint8Array.create(a);
|
||||
ar.set(cache);
|
||||
boolean tryWrite = AsyncHandlers.writeWholeFile(virtualFilesystem.indexeddb, filePath, a).bool;
|
||||
hasBeenAccessed = true;
|
||||
exists = exists || tryWrite;
|
||||
return tryWrite;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean delete() {
|
||||
if(!hasBeenDeleted && !(hasBeenAccessed && !exists)) {
|
||||
cacheHit = System.currentTimeMillis();
|
||||
if(!AsyncHandlers.deleteFile(virtualFilesystem.indexeddb, filePath).bool) {
|
||||
hasBeenAccessed = true;
|
||||
return false;
|
||||
}
|
||||
virtualFilesystem.fileMap.remove(filePath);
|
||||
hasBeenDeleted = true;
|
||||
hasBeenAccessed = true;
|
||||
exists = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean rename(String newName, boolean copy) {
|
||||
if(!hasBeenDeleted && !(hasBeenAccessed && !exists)) {
|
||||
cacheHit = System.currentTimeMillis();
|
||||
ArrayBuffer arr = AsyncHandlers.readWholeFile(virtualFilesystem.indexeddb, filePath);
|
||||
hasBeenAccessed = true;
|
||||
if(arr != null) {
|
||||
exists = true;
|
||||
if(!AsyncHandlers.writeWholeFile(virtualFilesystem.indexeddb, newName, arr).bool) {
|
||||
return false;
|
||||
}
|
||||
if(!copy && !AsyncHandlers.deleteFile(virtualFilesystem.indexeddb, filePath).bool) {
|
||||
return false;
|
||||
}
|
||||
}else {
|
||||
exists = false;
|
||||
}
|
||||
if(!copy) {
|
||||
virtualFilesystem.fileMap.remove(filePath);
|
||||
filePath = newName;
|
||||
virtualFilesystem.fileMap.put(newName, this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
if(hasBeenDeleted) {
|
||||
return false;
|
||||
}
|
||||
cacheHit = System.currentTimeMillis();
|
||||
if(hasBeenAccessed) {
|
||||
return exists;
|
||||
}
|
||||
exists = AsyncHandlers.fileExists(virtualFilesystem.indexeddb, filePath).bool;
|
||||
hasBeenAccessed = true;
|
||||
return exists;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final HashMap<String, VFSFile> fileMap = new HashMap();
|
||||
|
||||
public final String database;
|
||||
private final IDBDatabase indexeddb;
|
||||
|
||||
public static class VFSHandle {
|
||||
|
||||
public final boolean failedInit;
|
||||
public final boolean failedLocked;
|
||||
public final String failedError;
|
||||
public final VirtualFilesystem vfs;
|
||||
|
||||
public VFSHandle(boolean init, boolean locked, String error, VirtualFilesystem db) {
|
||||
failedInit = init;
|
||||
failedLocked = locked;
|
||||
failedError = error;
|
||||
vfs = db;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if(failedInit) {
|
||||
return "IDBFactory threw an exception, IndexedDB is most likely not supported in this browser." + (failedError == null ? "" : "\n\n" + failedError);
|
||||
}
|
||||
if(failedLocked) {
|
||||
return "The filesystem requested is already in use on a different tab.";
|
||||
}
|
||||
if(failedError != null) {
|
||||
return "The IDBFactory.open() request failed, reason: " + failedError;
|
||||
}
|
||||
return "Virtual Filesystem Object: " + vfs.database;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static VFSHandle openVFS(String db) {
|
||||
DatabaseOpen evt = AsyncHandlers.openDB(db);
|
||||
if(evt.failedInit) {
|
||||
return new VFSHandle(true, false, evt.failedError, null);
|
||||
}
|
||||
if(evt.failedLocked) {
|
||||
return new VFSHandle(false, true, null, null);
|
||||
}
|
||||
if(evt.failedError != null) {
|
||||
return new VFSHandle(false, false, evt.failedError, null);
|
||||
}
|
||||
return new VFSHandle(false, false, null, new VirtualFilesystem(db, evt.database));
|
||||
}
|
||||
|
||||
private VirtualFilesystem(String db, IDBDatabase idb) {
|
||||
database = db;
|
||||
indexeddb = idb;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
indexeddb.close();
|
||||
}
|
||||
|
||||
public VFSFile getFile(String path) {
|
||||
return getFile(path, false);
|
||||
}
|
||||
|
||||
public VFSFile getFile(String path, boolean cache) {
|
||||
VFSFile f = fileMap.get(path);
|
||||
if(f == null) {
|
||||
fileMap.put(path, f = new VFSFile(this, path, cache));
|
||||
}else {
|
||||
if(cache) {
|
||||
f.setCacheEnabled();
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
public boolean renameFile(String oldName, String newName, boolean copy) {
|
||||
return getFile(oldName).rename(newName, copy);
|
||||
}
|
||||
|
||||
public boolean deleteFile(String path) {
|
||||
return getFile(path).delete();
|
||||
}
|
||||
|
||||
public boolean fileExists(String path) {
|
||||
return getFile(path).exists();
|
||||
}
|
||||
|
||||
public List<String> listFiles(String prefix) {
|
||||
final ArrayList<String> list = new ArrayList();
|
||||
AsyncHandlers.iterateFiles(indexeddb, this, prefix, false, (v) -> {
|
||||
list.add(v.getPath());
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
public int deleteFiles(String prefix) {
|
||||
return AsyncHandlers.deleteFiles(indexeddb, prefix);
|
||||
}
|
||||
|
||||
public int iterateFiles(String prefix, boolean rw, VFSIterator itr) {
|
||||
return AsyncHandlers.iterateFiles(indexeddb, this, prefix, rw, itr);
|
||||
}
|
||||
|
||||
public int renameFiles(String oldPrefix, String newPrefix, boolean copy) {
|
||||
List<String> filesToCopy = listFiles(oldPrefix);
|
||||
int i = 0;
|
||||
for(String str : filesToCopy) {
|
||||
String f = VFile.createPath(newPrefix, str.substring(oldPrefix.length()));
|
||||
if(!renameFile(str, f, copy)) {
|
||||
System.err.println("Could not " + (copy ? "copy" : "rename") + " file \"" + str + "\" to \"" + f + "\" for some reason");
|
||||
}else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public void flushCache(long age) {
|
||||
long curr = System.currentTimeMillis();
|
||||
Iterator<VFSFile> files = fileMap.values().iterator();
|
||||
while(files.hasNext()) {
|
||||
if(curr - files.next().cacheHit > age) {
|
||||
files.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static class DatabaseOpen {
|
||||
|
||||
protected final boolean failedInit;
|
||||
protected final boolean failedLocked;
|
||||
protected final String failedError;
|
||||
|
||||
protected final IDBDatabase database;
|
||||
|
||||
protected DatabaseOpen(boolean init, boolean locked, String error, IDBDatabase db) {
|
||||
failedInit = init;
|
||||
failedLocked = locked;
|
||||
failedError = error;
|
||||
database = db;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JSBody(script = "return ((typeof indexedDB) !== 'undefined') ? indexedDB : null;")
|
||||
protected static native IDBFactory createIDBFactory();
|
||||
|
||||
protected static class AsyncHandlers {
|
||||
|
||||
@Async
|
||||
protected static native DatabaseOpen openDB(String name);
|
||||
|
||||
private static void openDB(String name, final AsyncCallback<DatabaseOpen> cb) {
|
||||
IDBFactory i = createIDBFactory();
|
||||
if(i == null) {
|
||||
cb.complete(new DatabaseOpen(false, false, "window.indexedDB was null or undefined", null));
|
||||
return;
|
||||
}
|
||||
final IDBOpenDBRequest f = i.open(name, 1);
|
||||
f.setOnBlocked(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(new DatabaseOpen(false, true, null, null));
|
||||
}
|
||||
});
|
||||
f.setOnSuccess(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(new DatabaseOpen(false, false, null, f.getResult()));
|
||||
}
|
||||
});
|
||||
f.setOnError(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(new DatabaseOpen(false, false, "open error", null));
|
||||
}
|
||||
});
|
||||
f.setOnUpgradeNeeded(new EventListener<IDBVersionChangeEvent>() {
|
||||
@Override
|
||||
public void handleEvent(IDBVersionChangeEvent evt) {
|
||||
f.getResult().createObjectStore("filesystem", IDBObjectStoreParameters.create().keyPath("path"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Async
|
||||
protected static native BooleanResult deleteFile(IDBDatabase db, String name);
|
||||
|
||||
private static void deleteFile(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
|
||||
IDBTransaction tx = db.transaction("filesystem", "readwrite");
|
||||
final IDBRequest r = tx.objectStore("filesystem").delete(makeTheFuckingKeyWork(name));
|
||||
|
||||
r.setOnSuccess(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(BooleanResult._new(true));
|
||||
}
|
||||
});
|
||||
r.setOnError(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(BooleanResult._new(false));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return (typeof obj === 'undefined') ? null : ((typeof obj.data === 'undefined') ? null : obj.data);")
|
||||
protected static native ArrayBuffer readRow(JSObject obj);
|
||||
|
||||
@JSBody(params = { "obj" }, script = "return [obj];")
|
||||
private static native JSObject makeTheFuckingKeyWork(String k);
|
||||
|
||||
@Async
|
||||
protected static native ArrayBuffer readWholeFile(IDBDatabase db, String name);
|
||||
|
||||
private static void readWholeFile(IDBDatabase db, String name, final AsyncCallback<ArrayBuffer> cb) {
|
||||
IDBTransaction tx = db.transaction("filesystem", "readonly");
|
||||
final IDBGetRequest r = tx.objectStore("filesystem").get(makeTheFuckingKeyWork(name));
|
||||
r.setOnSuccess(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(readRow(r.getResult()));
|
||||
}
|
||||
});
|
||||
r.setOnError(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(null);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@JSBody(params = { "k" }, script = "return ((typeof k) === \"string\") ? k : (((typeof k) === \"undefined\") ? null : (((typeof k[0]) === \"string\") ? k[0] : null));")
|
||||
private static native String readKey(JSObject k);
|
||||
|
||||
@JSBody(params = { "k" }, script = "return ((typeof k) === \"undefined\") ? null : (((typeof k.path) === \"undefined\") ? null : (((typeof k.path) === \"string\") ? k[0] : null));")
|
||||
private static native String readRowKey(JSObject r);
|
||||
|
||||
@Async
|
||||
protected static native Integer iterateFiles(IDBDatabase db, final VirtualFilesystem vfs, final String prefix, boolean rw, final VFSIterator itr);
|
||||
|
||||
private static void iterateFiles(IDBDatabase db, final VirtualFilesystem vfs, final String prefix, boolean rw, final VFSIterator itr, final AsyncCallback<Integer> cb) {
|
||||
IDBTransaction tx = db.transaction("filesystem", rw ? "readwrite" : "readonly");
|
||||
final IDBCursorRequest r = tx.objectStore("filesystem").openCursor();
|
||||
final int[] res = new int[1];
|
||||
r.setOnSuccess(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
IDBCursor c = r.getResult();
|
||||
if(c == null || c.getKey() == null || c.getValue() == null) {
|
||||
cb.complete(res[0]);
|
||||
return;
|
||||
}
|
||||
String k = readKey(c.getKey());
|
||||
if(k != null) {
|
||||
if(k.startsWith(prefix)) {
|
||||
int ci = res[0]++;
|
||||
try {
|
||||
itr.next(VIteratorFile.create(ci, vfs, c));
|
||||
}catch(VFSIterator.BreakLoop ex) {
|
||||
cb.complete(res[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
c.doContinue();
|
||||
}
|
||||
});
|
||||
r.setOnError(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(res[0] > 0 ? res[0] : -1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Async
|
||||
protected static native Integer deleteFiles(IDBDatabase db, final String prefix);
|
||||
|
||||
private static void deleteFiles(IDBDatabase db, final String prefix, final AsyncCallback<Integer> cb) {
|
||||
IDBTransaction tx = db.transaction("filesystem", "readwrite");
|
||||
final IDBCursorRequest r = tx.objectStore("filesystem").openCursor();
|
||||
final int[] res = new int[1];
|
||||
r.setOnSuccess(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
IDBCursor c = r.getResult();
|
||||
if(c == null || c.getKey() == null || c.getValue() == null) {
|
||||
cb.complete(res[0]);
|
||||
return;
|
||||
}
|
||||
String k = readKey(c.getKey());
|
||||
if(k != null) {
|
||||
if(k.startsWith(prefix)) {
|
||||
c.delete();
|
||||
++res[0];
|
||||
}
|
||||
}
|
||||
c.doContinue();
|
||||
}
|
||||
});
|
||||
r.setOnError(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(res[0] > 0 ? res[0] : -1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Async
|
||||
protected static native BooleanResult fileExists(IDBDatabase db, String name);
|
||||
|
||||
private static void fileExists(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
|
||||
IDBTransaction tx = db.transaction("filesystem", "readonly");
|
||||
final IDBCountRequest r = tx.objectStore("filesystem").count(makeTheFuckingKeyWork(name));
|
||||
r.setOnSuccess(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(BooleanResult._new(r.getResult() > 0));
|
||||
}
|
||||
});
|
||||
r.setOnError(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(BooleanResult._new(false));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@JSBody(params = { "pat", "dat" }, script = "return { path: pat, data: dat };")
|
||||
protected static native JSObject writeRow(String name, ArrayBuffer data);
|
||||
|
||||
@Async
|
||||
protected static native BooleanResult writeWholeFile(IDBDatabase db, String name, ArrayBuffer data);
|
||||
|
||||
private static void writeWholeFile(IDBDatabase db, String name, ArrayBuffer data, final AsyncCallback<BooleanResult> cb) {
|
||||
IDBTransaction tx = db.transaction("filesystem", "readwrite");
|
||||
final IDBRequest r = tx.objectStore("filesystem").put(writeRow(name, data));
|
||||
|
||||
r.setOnSuccess(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(BooleanResult._new(true));
|
||||
}
|
||||
});
|
||||
r.setOnError(new EventHandler() {
|
||||
@Override
|
||||
public void handleEvent() {
|
||||
cb.complete(BooleanResult._new(false));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static byte[] utf8(String str) {
|
||||
if(str == null) return null;
|
||||
return str.getBytes(Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
public static String utf8(byte[] str) {
|
||||
if(str == null) return null;
|
||||
return new String(str, Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
public static String CRLFtoLF(String str) {
|
||||
if(str == null) return null;
|
||||
str = str.indexOf('\r') != -1 ? str.replace("\r", "") : str;
|
||||
str = str.trim();
|
||||
if(str.endsWith("\n")) {
|
||||
str = str.substring(0, str.length() - 1);
|
||||
}
|
||||
if(str.startsWith("\n")) {
|
||||
str = str.substring(1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String[] lines(String str) {
|
||||
if(str == null) return null;
|
||||
return CRLFtoLF(str).split("\n");
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user