mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 10:58:15 -05:00
Update #37 - Touch support without userscript, many other feats
This commit is contained in:
@ -25,6 +25,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteBuffers(this);
|
||||
@ -40,6 +44,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteVertexArrays(this);
|
||||
@ -55,6 +63,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteTextures(this);
|
||||
@ -70,6 +82,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteProgram(this);
|
||||
@ -85,6 +101,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
}
|
||||
@ -99,6 +119,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteShader(this);
|
||||
@ -114,6 +138,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteFramebuffer(this);
|
||||
@ -129,6 +157,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteRenderbuffer(this);
|
||||
@ -144,6 +176,10 @@ class OpenGLObjects {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
PlatformOpenGL._wglDeleteQueries(this);
|
||||
|
@ -7,6 +7,7 @@ import java.awt.Desktop;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.Dialog.ModalExclusionType;
|
||||
import java.awt.Dialog.ModalityType;
|
||||
import java.io.File;
|
||||
@ -14,16 +15,23 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.MainMenuCreditsDialog;
|
||||
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-2023 lax1dude, ayunami2000. All Rights Reserved.
|
||||
@ -49,10 +57,23 @@ public class PlatformApplication {
|
||||
}
|
||||
|
||||
public static void openLink(String url) {
|
||||
URI safeURL;
|
||||
try {
|
||||
Desktop.getDesktop().browse(new URI(url));
|
||||
safeURL = new URI(url);
|
||||
String proto = safeURL.getScheme();
|
||||
if(!proto.equalsIgnoreCase("http") && !proto.equalsIgnoreCase("https")) {
|
||||
throw new IllegalArgumentException("Suspicious protocol: " + proto);
|
||||
}
|
||||
}catch(URISyntaxException | IllegalArgumentException ex) {
|
||||
PlatformRuntime.logger.error("Refusing to open invalid URL: {}", url);
|
||||
PlatformRuntime.logger.error(ex);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Desktop.getDesktop().browse(safeURL);
|
||||
} catch (Throwable var5) {
|
||||
EagRuntime.debugPrintStackTrace(var5);
|
||||
PlatformRuntime.logger.error("Failed to browse to URL: {}", safeURL.toString());
|
||||
PlatformRuntime.logger.error(var5);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,9 +119,40 @@ public class PlatformApplication {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final DateFormat dateFormatSS = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
|
||||
private static final File screeshotsDir = new File("screenshots");
|
||||
|
||||
public static String saveScreenshot() {
|
||||
return "nothing";
|
||||
if(!screeshotsDir.isDirectory() && !screeshotsDir.mkdirs()) {
|
||||
PlatformRuntime.logger.error("Failed to create screenshots directory: {}", screeshotsDir.getAbsolutePath());
|
||||
return "nothing";
|
||||
}
|
||||
String name = "screenshot_" + dateFormatSS.format(new Date()).toString() + ".png";
|
||||
int w = PlatformInput.getWindowWidth();
|
||||
int h = PlatformInput.getWindowHeight();
|
||||
ByteBuffer screenshotBuffer = PlatformRuntime.allocateByteBuffer(w * h * 4);
|
||||
PlatformOpenGL._wglReadPixels(0, 0, w, h, RealOpenGLEnums.GL_RGBA, RealOpenGLEnums.GL_UNSIGNED_BYTE, screenshotBuffer);
|
||||
BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
int i;
|
||||
for(int y = 0; y < h; ++y) {
|
||||
for(int x = 0; x < w; ++x) {
|
||||
i = (x + (h - y - 1) * w) << 2;
|
||||
bufferedImage.setRGB(x, y,
|
||||
((screenshotBuffer.get(i) & 0xFF) << 16) | ((screenshotBuffer.get(i + 1) & 0xFF) << 8)
|
||||
| (screenshotBuffer.get(i + 2) & 0xFF) | 0xFF000000);
|
||||
}
|
||||
}
|
||||
PlatformRuntime.freeByteBuffer(screenshotBuffer);
|
||||
File screenshotFile = new File(screeshotsDir, name);
|
||||
try {
|
||||
ImageIO.write(bufferedImage, "PNG", screenshotFile);
|
||||
}catch(IOException ex) {
|
||||
PlatformRuntime.logger.error("Failed to write screenshot: {}", screenshotFile.getAbsolutePath());
|
||||
return "nothing";
|
||||
}
|
||||
PlatformRuntime.logger.info("Saved screenshot to: {}", screenshotFile.getAbsolutePath());
|
||||
return name;
|
||||
}
|
||||
|
||||
public static void showPopup(String msg) {
|
||||
@ -127,6 +179,7 @@ public class PlatformApplication {
|
||||
public static void displayFileChooser(final String mime, final String ext) {
|
||||
if(!fileChooserOpen) {
|
||||
fileChooserOpen = true;
|
||||
clearFileChooserResult();
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -43,7 +43,11 @@ public class PlatformAssets {
|
||||
}
|
||||
}
|
||||
|
||||
public static final byte[] getResourceBytes(String path) {
|
||||
public static boolean getResourceExists(String path) {
|
||||
return (new File("resources", path)).isFile();
|
||||
}
|
||||
|
||||
public static byte[] getResourceBytes(String path) {
|
||||
File loadFile = new File("resources", path);
|
||||
byte[] ret = new byte[(int) loadFile.length()];
|
||||
try(FileInputStream is = new FileInputStream(loadFile)) {
|
||||
@ -56,8 +60,12 @@ public class PlatformAssets {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final ImageData loadImageFile(InputStream data) {
|
||||
|
||||
public static ImageData loadImageFile(InputStream data) {
|
||||
return loadImageFile(data, "image/png");
|
||||
}
|
||||
|
||||
public static ImageData loadImageFile(InputStream data, String mime) {
|
||||
try {
|
||||
BufferedImage img = ImageIO.read(data);
|
||||
if(img == null) {
|
||||
@ -81,9 +89,13 @@ public class PlatformAssets {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final ImageData loadImageFile(byte[] data) {
|
||||
return loadImageFile(new EaglerInputStream(data));
|
||||
|
||||
public static ImageData loadImageFile(byte[] data) {
|
||||
return loadImageFile(new EaglerInputStream(data), "image/png");
|
||||
}
|
||||
|
||||
|
||||
public static ImageData loadImageFile(byte[] data, String mime) {
|
||||
return loadImageFile(new EaglerInputStream(data), mime);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public class PlatformAudio {
|
||||
|
||||
protected PaulscodeAudioHandle(String sourceName) {
|
||||
this.sourceName = sourceName;
|
||||
this.stall = System.currentTimeMillis();
|
||||
this.stall = PlatformRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,7 +64,7 @@ public class PlatformAudio {
|
||||
|
||||
@Override
|
||||
public void restart() {
|
||||
this.stall = System.currentTimeMillis();
|
||||
this.stall = PlatformRuntime.steadyTimeMillis();
|
||||
sndSystem.rewind(sourceName);
|
||||
sndSystem.play(sourceName);
|
||||
}
|
||||
@ -91,7 +91,7 @@ public class PlatformAudio {
|
||||
|
||||
@Override
|
||||
public boolean shouldFree() {
|
||||
return !sndSystem.playing(sourceName) && System.currentTimeMillis() - this.stall > 250l; //TODO: I hate this hack
|
||||
return !sndSystem.playing(sourceName) && PlatformRuntime.steadyTimeMillis() - this.stall > 250l; //TODO: I hate this hack
|
||||
}
|
||||
|
||||
}
|
||||
@ -125,7 +125,7 @@ public class PlatformAudio {
|
||||
private static SoundSystem sndSystem = null;
|
||||
|
||||
static void platformInitialize() {
|
||||
logger.info("Eaglercraft still uses Paul Lamb's SoundSystem but with LWJGL3");
|
||||
logger.info("Eaglercraft uses Paul Lamb's SoundSystem (with LWJGL3)");
|
||||
logger.info(" \"Author: Paul Lamb, www.paulscode.com\"");
|
||||
try {
|
||||
SoundSystemConfig.addLibrary(LibraryLWJGLOpenAL.class);
|
||||
|
@ -2,7 +2,6 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DebugFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.JDBCFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.JDBCFilesystemConverter;
|
||||
@ -28,104 +27,50 @@ public class PlatformFilesystem {
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("PlatformFilesystem");
|
||||
|
||||
@Deprecated
|
||||
public static final File debugFilesystemRoot = (new File("filesystem/sp")).getAbsoluteFile();
|
||||
|
||||
private static IFilesystemProvider provider = null;
|
||||
public static final File filesystemsRoot = (new File("filesystem")).getAbsoluteFile();
|
||||
|
||||
public static String jdbcUri = null;
|
||||
public static String jdbcDriver = null;
|
||||
private static final boolean isLegacyFolder = checkLegacy();
|
||||
|
||||
public static void initialize() {
|
||||
if(provider == null) {
|
||||
if(jdbcUri != null && jdbcDriver != null) {
|
||||
provider = JDBCFilesystem.initialize(jdbcUri, jdbcDriver);
|
||||
private static boolean checkLegacy() {
|
||||
if(!debugFilesystemRoot.isDirectory()) return false;
|
||||
String[] str = debugFilesystemRoot.list();
|
||||
return str != null && str.length > 0;
|
||||
}
|
||||
|
||||
public static IEaglerFilesystem initializePersist(String dbName) {
|
||||
String jdbcUri = System.getProperty("eagler.jdbc." + dbName + ".uri");
|
||||
String jdbcDriver = System.getProperty("eagler.jdbc." + dbName + ".driver");
|
||||
if(jdbcUri != null && jdbcDriver != null) {
|
||||
try {
|
||||
IEaglerFilesystem provider = JDBCFilesystem.initialize(dbName, jdbcUri, jdbcDriver);
|
||||
if(((JDBCFilesystem)provider).isNewFilesystem() && debugFilesystemRoot.isDirectory() && debugFilesystemRoot.list().length > 0) {
|
||||
JDBCFilesystemConverter.convertFilesystem("Converting filesystem, please wait...", debugFilesystemRoot, provider, true);
|
||||
}
|
||||
return provider;
|
||||
}catch(Throwable t) {
|
||||
logger.error("Could not open jdbc-based filesystem: {}", dbName);
|
||||
logger.error(t);
|
||||
return null;
|
||||
}
|
||||
}else {
|
||||
File f;
|
||||
if(isLegacyFolder && (dbName.equals("worlds") || dbName.equals("resourcePacks"))) {
|
||||
f = debugFilesystemRoot;
|
||||
logger.info("Note: filesystem \"{}\" will be stored in the legacy \"sp\" folder because it exists and is not empty", dbName);
|
||||
}else {
|
||||
provider = DebugFilesystem.initialize(debugFilesystemRoot);
|
||||
f = new File(filesystemsRoot, dbName);
|
||||
}
|
||||
try {
|
||||
return DebugFilesystem.initialize(dbName, f);
|
||||
}catch(Throwable t) {
|
||||
logger.error("Could not open folder-based filesystem: {}", dbName);
|
||||
logger.error(t);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setUseJDBC(String uri) {
|
||||
jdbcUri = uri;
|
||||
}
|
||||
|
||||
public static void setJDBCDriverClass(String driver) {
|
||||
jdbcDriver = driver;
|
||||
}
|
||||
|
||||
public static interface IFilesystemProvider {
|
||||
|
||||
boolean eaglerDelete(String pathName);
|
||||
|
||||
ByteBuffer eaglerRead(String pathName);
|
||||
|
||||
void eaglerWrite(String pathName, ByteBuffer data);
|
||||
|
||||
boolean eaglerExists(String pathName);
|
||||
|
||||
boolean eaglerMove(String pathNameOld, String pathNameNew);
|
||||
|
||||
int eaglerCopy(String pathNameOld, String pathNameNew);
|
||||
|
||||
int eaglerSize(String pathName);
|
||||
|
||||
void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive);
|
||||
|
||||
}
|
||||
|
||||
private static void throwNotInitialized() {
|
||||
throw new UnsupportedOperationException("Filesystem has not been initialized!");
|
||||
}
|
||||
|
||||
public static boolean eaglerDelete(String pathName) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
return provider.eaglerDelete(pathName);
|
||||
}
|
||||
|
||||
public static ByteBuffer eaglerRead(String pathName) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
return provider.eaglerRead(pathName);
|
||||
}
|
||||
|
||||
public static void eaglerWrite(String pathName, ByteBuffer data) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
provider.eaglerWrite(pathName, data);
|
||||
}
|
||||
|
||||
public static boolean eaglerExists(String pathName) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
return provider.eaglerExists(pathName);
|
||||
}
|
||||
|
||||
public static boolean eaglerMove(String pathNameOld, String pathNameNew) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
return provider.eaglerMove(pathNameOld, pathNameNew);
|
||||
}
|
||||
|
||||
public static int eaglerCopy(String pathNameOld, String pathNameNew) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
return provider.eaglerCopy(pathNameOld, pathNameNew);
|
||||
}
|
||||
|
||||
public static int eaglerSize(String pathName) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
return provider.eaglerSize(pathName);
|
||||
}
|
||||
|
||||
public static void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
|
||||
if(provider == null) throwNotInitialized();
|
||||
provider.eaglerIterate(pathName, itr, recursive);
|
||||
}
|
||||
|
||||
public static void platformShutdown() {
|
||||
if(provider != null) {
|
||||
if(provider instanceof JDBCFilesystem) {
|
||||
((JDBCFilesystem)provider).shutdown();
|
||||
}
|
||||
provider = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,20 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.glfw.GLFWGamepadState;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -34,6 +39,7 @@ public class PlatformInput {
|
||||
|
||||
private static boolean windowFocused = true;
|
||||
private static boolean windowResized = true;
|
||||
private static boolean windowResized2 = true;
|
||||
|
||||
private static boolean windowCursorEntered = true;
|
||||
private static boolean windowMouseGrabbed = false;
|
||||
@ -46,7 +52,7 @@ public class PlatformInput {
|
||||
private static int windowWidth = 640;
|
||||
private static int windowHeight = 480;
|
||||
|
||||
private static final List<KeyboardEvent> keyboardEventList = new LinkedList();
|
||||
private static final List<KeyboardEvent> keyboardEventList = new LinkedList<>();
|
||||
private static KeyboardEvent currentKeyboardEvent = null;
|
||||
|
||||
private static final char[] keyboardReleaseEventChars = new char[256];
|
||||
@ -56,7 +62,7 @@ public class PlatformInput {
|
||||
|
||||
public static boolean lockKeys = false;
|
||||
|
||||
private static final List<Character> keyboardCharList = new LinkedList();
|
||||
private static final List<Character> keyboardCharList = new LinkedList<>();
|
||||
|
||||
private static boolean vsync = true;
|
||||
private static boolean glfwVSyncState = false;
|
||||
@ -75,8 +81,8 @@ public class PlatformInput {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final List<MouseEvent> mouseEventList = new LinkedList();
|
||||
|
||||
private static final List<MouseEvent> mouseEventList = new LinkedList<>();
|
||||
private static MouseEvent currentMouseEvent = null;
|
||||
|
||||
private static class MouseEvent {
|
||||
@ -97,6 +103,44 @@ public class PlatformInput {
|
||||
|
||||
}
|
||||
|
||||
private static final List<Gamepad> gamepadList = new ArrayList<>();
|
||||
private static int selectedGamepad = -1;
|
||||
private static String selectedGamepadName = null;
|
||||
private static String selectedGamepadUUID = null;
|
||||
private static final boolean[] gamepadButtonStates = new boolean[24];
|
||||
private static final float[] gamepadAxisStates = new float[4];
|
||||
|
||||
private static class Gamepad {
|
||||
|
||||
protected final int gamepadId;
|
||||
protected final String gamepadName;
|
||||
protected final String gamepadUUID;
|
||||
|
||||
protected Gamepad(int gamepadId, String gamepadName, String gamepadUUID) {
|
||||
this.gamepadId = gamepadId;
|
||||
this.gamepadName = gamepadName;
|
||||
this.gamepadUUID = gamepadUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(gamepadId, gamepadName, gamepadUUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Gamepad other = (Gamepad) obj;
|
||||
return gamepadId == other.gamepadId && Objects.equals(gamepadName, other.gamepadName)
|
||||
&& Objects.equals(gamepadUUID, other.gamepadUUID);
|
||||
}
|
||||
}
|
||||
|
||||
static void initHooks(long glfwWindow) {
|
||||
win = glfwWindow;
|
||||
|
||||
@ -121,13 +165,20 @@ public class PlatformInput {
|
||||
|
||||
windowWidth = v1[0];
|
||||
windowHeight = v2[0];
|
||||
windowResized = true;
|
||||
windowResized2 = true;
|
||||
|
||||
glfwSetFramebufferSizeCallback(glfwWindow, (window, width, height) -> {
|
||||
windowWidth = width;
|
||||
windowHeight = height;
|
||||
windowResized = true;
|
||||
if(windowWidth != width || windowHeight != height) {
|
||||
windowWidth = width;
|
||||
windowHeight = height;
|
||||
windowResized = true;
|
||||
windowResized2 = true;
|
||||
}
|
||||
});
|
||||
|
||||
windowFocused = true;
|
||||
|
||||
glfwSetWindowFocusCallback(glfwWindow, (window, focused) -> {
|
||||
windowFocused = focused;
|
||||
});
|
||||
@ -199,6 +250,15 @@ public class PlatformInput {
|
||||
if(!fullscreen && startupFullscreen) {
|
||||
toggleFullscreen();
|
||||
}
|
||||
|
||||
gamepadEnumerateDevices();
|
||||
|
||||
glfwSetJoystickCallback((jid, event) -> {
|
||||
if(event == GLFW_DISCONNECTED && jid == selectedGamepad) {
|
||||
selectedGamepad = -1;
|
||||
}
|
||||
gamepadEnumerateDevices();
|
||||
});
|
||||
}
|
||||
|
||||
public static int getWindowWidth() {
|
||||
@ -209,6 +269,22 @@ public class PlatformInput {
|
||||
return windowHeight;
|
||||
}
|
||||
|
||||
public static int getVisualViewportX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getVisualViewportY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getVisualViewportW() {
|
||||
return windowWidth;
|
||||
}
|
||||
|
||||
public static int getVisualViewportH() {
|
||||
return windowHeight;
|
||||
}
|
||||
|
||||
public static boolean getWindowFocused() {
|
||||
return windowFocused;
|
||||
}
|
||||
@ -240,6 +316,12 @@ public class PlatformInput {
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean wasVisualViewportResized() {
|
||||
boolean b = windowResized2;
|
||||
windowResized2 = false;
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean keyboardNext() {
|
||||
if(keyboardEventList.size() > 0) {
|
||||
currentKeyboardEvent = keyboardEventList.remove(0);
|
||||
@ -274,6 +356,33 @@ public class PlatformInput {
|
||||
}
|
||||
}
|
||||
|
||||
public static void keyboardFireEvent(EnumFireKeyboardEvent eventType, int eagKey, char keyChar) {
|
||||
switch(eventType) {
|
||||
case KEY_DOWN:
|
||||
keyboardCharList.add(keyChar);
|
||||
keyboardEventList.add(new KeyboardEvent(eagKey, true, false));
|
||||
break;
|
||||
case KEY_UP:
|
||||
if(eagKey >= 0 && eagKey < keyboardReleaseEventChars.length) {
|
||||
keyboardReleaseEventChars[eagKey] = keyChar;
|
||||
}
|
||||
keyboardEventList.add(new KeyboardEvent(eagKey, false, false));
|
||||
break;
|
||||
case KEY_REPEAT:
|
||||
keyboardCharList.add(keyChar);
|
||||
keyboardEventList.add(new KeyboardEvent(eagKey, true, true));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if(keyboardEventList.size() > 64) {
|
||||
keyboardEventList.remove(0);
|
||||
}
|
||||
if(keyboardCharList.size() > 64) {
|
||||
keyboardCharList.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean keyboardGetEventKeyState() {
|
||||
return currentKeyboardEvent.pressed;
|
||||
}
|
||||
@ -315,6 +424,44 @@ public class PlatformInput {
|
||||
}
|
||||
}
|
||||
|
||||
public static void mouseFireMoveEvent(EnumFireMouseEvent eventType, int posX, int posY) {
|
||||
if(eventType == EnumFireMouseEvent.MOUSE_MOVE) {
|
||||
mouseEventList.add(new MouseEvent(-1, false, posX, posY, 0.0f));
|
||||
if(mouseEventList.size() > 64) {
|
||||
mouseEventList.remove(0);
|
||||
}
|
||||
}else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void mouseFireButtonEvent(EnumFireMouseEvent eventType, int posX, int posY, int button) {
|
||||
switch(eventType) {
|
||||
case MOUSE_DOWN:
|
||||
mouseEventList.add(new MouseEvent(button, true, posX, posY, 0.0f));
|
||||
break;
|
||||
case MOUSE_UP:
|
||||
mouseEventList.add(new MouseEvent(button, false, posX, posY, 0.0f));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if(mouseEventList.size() > 64) {
|
||||
mouseEventList.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void mouseFireWheelEvent(EnumFireMouseEvent eventType, int posX, int posY, float wheel) {
|
||||
if(eventType == EnumFireMouseEvent.MOUSE_WHEEL) {
|
||||
mouseEventList.add(new MouseEvent(-1, false, posX, posY, wheel));
|
||||
if(mouseEventList.size() > 64) {
|
||||
mouseEventList.remove(0);
|
||||
}
|
||||
}else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean mouseGetEventButtonState() {
|
||||
return currentMouseEvent.pressed;
|
||||
}
|
||||
@ -366,6 +513,10 @@ public class PlatformInput {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean mouseGrabSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isPointerLocked() {
|
||||
return windowMouseGrabbed;
|
||||
}
|
||||
@ -404,6 +555,10 @@ public class PlatformInput {
|
||||
functionKeyModifier = KeyboardConstants.getGLFWKeyFromEagler(key);
|
||||
}
|
||||
|
||||
public static boolean supportsFullscreen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean fullscreen = false;
|
||||
private static boolean startupFullscreen = false;
|
||||
private static int[] lastPos = new int[4];
|
||||
@ -483,4 +638,247 @@ public class PlatformInput {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean touchNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static EnumTouchEvent touchGetEventType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int touchGetEventTouchPointCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int touchGetEventTouchX(int pointId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int touchGetEventTouchY(int pointId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float touchGetEventTouchRadiusX(int pointId) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public static float touchGetEventTouchRadiusY(int pointId) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public static float touchGetEventTouchRadiusMixed(int pointId) {
|
||||
return touchGetEventTouchRadiusX(pointId) * 0.5f + touchGetEventTouchRadiusY(pointId) * 0.5f;
|
||||
}
|
||||
|
||||
public static float touchGetEventTouchForce(int pointId) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public static int touchGetEventTouchPointUID(int pointId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int touchPointCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int touchPointX(int pointId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int touchPointY(int pointId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float touchRadiusX(int pointId) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public static float touchRadiusY(int pointId) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public static float touchRadiusMixed(int pointId) {
|
||||
return touchRadiusX(pointId) * 0.5f + touchRadiusY(pointId) * 0.5f;
|
||||
}
|
||||
|
||||
public static float touchForce(int pointId) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public static int touchPointUID(int pointId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void touchSetOpenKeyboardZone(int x, int y, int w, int h) {
|
||||
|
||||
}
|
||||
|
||||
public static void touchCloseDeviceKeyboard() {
|
||||
|
||||
}
|
||||
|
||||
public static boolean touchIsDeviceKeyboardOpenMAYBE() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String touchGetPastedString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void gamepadEnumerateDevices() {
|
||||
if(selectedGamepad != -1 && !glfwJoystickIsGamepad(selectedGamepad)) {
|
||||
selectedGamepad = -1;
|
||||
}
|
||||
List<Gamepad> oldList = null;
|
||||
if(!gamepadList.isEmpty()) {
|
||||
oldList = new ArrayList<>(gamepadList);
|
||||
gamepadList.clear();
|
||||
}
|
||||
for(int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_16; ++i) {
|
||||
if(glfwJoystickIsGamepad(i)) {
|
||||
gamepadList.add(new Gamepad(i, gamepadMakeName(i), glfwGetJoystickGUID(i)));
|
||||
}
|
||||
}
|
||||
vigg: if(selectedGamepad != -1) {
|
||||
for(int i = 0, l = gamepadList.size(); i < l; ++i) {
|
||||
Gamepad gp = gamepadList.get(i);
|
||||
if(gp.gamepadId == selectedGamepad && gp.gamepadUUID.equals(selectedGamepadUUID)) {
|
||||
break vigg;
|
||||
}
|
||||
}
|
||||
selectedGamepad = -1;
|
||||
}
|
||||
if(oldList == null) {
|
||||
if(!gamepadList.isEmpty()) {
|
||||
for(int i = 0, l = gamepadList.size(); i < l; ++i) {
|
||||
PlatformRuntime.logger.info("Found controller: {}", gamepadList.get(i).gamepadName);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if(gamepadList.isEmpty()) {
|
||||
for(int i = 0, l = oldList.size(); i < l; ++i) {
|
||||
PlatformRuntime.logger.info("Lost controller: {}", oldList.get(i).gamepadName);
|
||||
}
|
||||
}else {
|
||||
Set<String> oldGamepadUUIDs = new HashSet<>();
|
||||
for(int i = 0, l = oldList.size(); i < l; ++i) {
|
||||
oldGamepadUUIDs.add(oldList.get(i).gamepadUUID);
|
||||
}
|
||||
Set<String> newGamepadUUIDs = new HashSet<>();
|
||||
for(int i = 0, l = gamepadList.size(); i < l; ++i) {
|
||||
newGamepadUUIDs.add(gamepadList.get(i).gamepadUUID);
|
||||
}
|
||||
for(int i = 0, l = oldList.size(); i < l; ++i) {
|
||||
Gamepad g = oldList.get(i);
|
||||
if(!newGamepadUUIDs.contains(g.gamepadUUID)) {
|
||||
PlatformRuntime.logger.info("Lost controller: {}", g.gamepadName);
|
||||
}
|
||||
}
|
||||
for(int i = 0, l = gamepadList.size(); i < l; ++i) {
|
||||
Gamepad g = gamepadList.get(i);
|
||||
if(!oldGamepadUUIDs.contains(g.gamepadUUID)) {
|
||||
PlatformRuntime.logger.info("Found controller: {}", g.gamepadName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String gamepadMakeName(int glfwId) {
|
||||
String s = glfwGetGamepadName(glfwId);
|
||||
if(s.endsWith(" (GLFW)")) {
|
||||
s = s.substring(0, s.length() - 7);
|
||||
}
|
||||
return glfwGetJoystickName(glfwId) + " (" + s + ")";
|
||||
}
|
||||
|
||||
public static int gamepadGetValidDeviceCount() {
|
||||
return gamepadList.size();
|
||||
}
|
||||
|
||||
public static String gamepadGetDeviceName(int deviceId) {
|
||||
if(deviceId >= 0 && deviceId < gamepadList.size()) {
|
||||
return gamepadList.get(deviceId).gamepadName;
|
||||
}else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public static void gamepadSetSelectedDevice(int deviceId) {
|
||||
gamepadReset();
|
||||
if(deviceId >= 0 && deviceId < gamepadList.size()) {
|
||||
selectedGamepad = gamepadList.get(deviceId).gamepadId;
|
||||
if(!glfwJoystickIsGamepad(selectedGamepad)) {
|
||||
selectedGamepad = -1;
|
||||
}
|
||||
}else {
|
||||
selectedGamepad = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void gamepadReset() {
|
||||
for(int i = 0; i < gamepadButtonStates.length; ++i) {
|
||||
gamepadButtonStates[i] = false;
|
||||
}
|
||||
for(int i = 0; i < gamepadAxisStates.length; ++i) {
|
||||
gamepadAxisStates[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public static void gamepadUpdate() {
|
||||
gamepadReset();
|
||||
if(selectedGamepad != -1) {
|
||||
if(!glfwJoystickIsGamepad(selectedGamepad)) {
|
||||
selectedGamepad = -1;
|
||||
return;
|
||||
}
|
||||
try(MemoryStack ms = MemoryStack.stackPush()) {
|
||||
GLFWGamepadState state = GLFWGamepadState.calloc(ms);
|
||||
glfwGetGamepadState(selectedGamepad, state);
|
||||
java.nio.FloatBuffer axes = state.axes();
|
||||
axes.get(gamepadAxisStates);
|
||||
java.nio.ByteBuffer buttons = state.buttons();
|
||||
for(int i = 0, l = buttons.remaining(); i < l && i < gamepadButtonStates.length; ++i) {
|
||||
boolean v = buttons.get() != (byte)0;
|
||||
int j = GamepadConstants.getEaglerButtonFromGLFW(i);
|
||||
if(j != -1) {
|
||||
gamepadButtonStates[j] = v;
|
||||
}
|
||||
}
|
||||
gamepadButtonStates[GamepadConstants.GAMEPAD_LEFT_TRIGGER] = axes.get() > 0.4f;
|
||||
gamepadButtonStates[GamepadConstants.GAMEPAD_RIGHT_TRIGGER] = axes.get() > 0.4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean gamepadIsValid() {
|
||||
return selectedGamepad != -1;
|
||||
}
|
||||
|
||||
public static String gamepadGetName() {
|
||||
return selectedGamepad != -1 ? selectedGamepadName : "Unknown";
|
||||
}
|
||||
|
||||
public static boolean gamepadGetButtonState(int button) {
|
||||
return selectedGamepad != -1 && button >= 0 && button < gamepadButtonStates.length ? gamepadButtonStates[button] : false;
|
||||
}
|
||||
|
||||
public static float gamepadGetAxis(int axis) {
|
||||
return selectedGamepad != -1 && axis >= 0 && axis < gamepadAxisStates.length ? gamepadAxisStates[axis] : 0.0f;
|
||||
}
|
||||
|
||||
public static float getDPI() {
|
||||
float[] dpiX = new float[1];
|
||||
float[] dpiY = new float[1];
|
||||
glfwGetWindowContentScale(win, dpiX, dpiY);
|
||||
float ret = dpiX[0] * 0.5f + dpiY[0] * 0.5f;
|
||||
if(ret <= 0.0f) {
|
||||
ret = 1.0f;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,17 +2,13 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.java_websocket.enums.ReadyState;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DesktopWebSocketClient;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -28,124 +24,22 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
*/
|
||||
public class PlatformNetworking {
|
||||
|
||||
static final Logger networkLogger = LogManager.getLogger("PlatformNetworking");
|
||||
private static final Logger logger = LogManager.getLogger("PlatformNetworking");
|
||||
|
||||
private static WebSocketPlayClient wsPlayClient = null;
|
||||
static EnumEaglerConnectionState playConnectState = EnumEaglerConnectionState.CLOSED;
|
||||
static EnumServerRateLimit serverRateLimit = null;
|
||||
|
||||
static String currentURI = null;
|
||||
|
||||
public static EnumEaglerConnectionState playConnectionState() {
|
||||
return ((wsPlayClient == null || wsPlayClient.isClosed()) && playConnectState == EnumEaglerConnectionState.CONNECTING) ? EnumEaglerConnectionState.FAILED :
|
||||
((wsPlayClient != null && wsPlayClient.getReadyState() == ReadyState.NOT_YET_CONNECTED) ? EnumEaglerConnectionState.CONNECTING :
|
||||
(((wsPlayClient == null || wsPlayClient.isClosed()) && playConnectState != EnumEaglerConnectionState.FAILED) ? EnumEaglerConnectionState.CLOSED : playConnectState));
|
||||
}
|
||||
|
||||
public static void startPlayConnection(String destination) {
|
||||
if(!playConnectionState().isClosed()) {
|
||||
networkLogger.warn("Tried connecting to a server while already connected to a different server!");
|
||||
playDisconnect();
|
||||
}
|
||||
|
||||
currentURI = destination;
|
||||
|
||||
synchronized(playPackets) {
|
||||
playPackets.clear();
|
||||
}
|
||||
|
||||
playConnectState = EnumEaglerConnectionState.CONNECTING;
|
||||
networkLogger.info("Connecting to server: {}", destination);
|
||||
|
||||
URI u;
|
||||
|
||||
public static IWebSocketClient openWebSocket(String socketURI) {
|
||||
try {
|
||||
u = new URI(destination);
|
||||
}catch(URISyntaxException ex) {
|
||||
networkLogger.error("Invalid server URI: {}", destination);
|
||||
playConnectState = EnumEaglerConnectionState.FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
wsPlayClient = new WebSocketPlayClient(u);
|
||||
wsPlayClient.connect();
|
||||
}
|
||||
|
||||
public static void playDisconnect() {
|
||||
if(!playConnectionState().isClosed() && wsPlayClient != null) {
|
||||
try {
|
||||
wsPlayClient.closeBlocking();
|
||||
} catch (InterruptedException e) {
|
||||
// :(
|
||||
}
|
||||
playConnectState = EnumEaglerConnectionState.CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<byte[]> playPackets = new LinkedList();
|
||||
|
||||
public static byte[] readPlayPacket() {
|
||||
synchronized(playPackets) {
|
||||
return playPackets.size() > 0 ? playPackets.remove(0) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<byte[]> readAllPacket() {
|
||||
synchronized(playPackets) {
|
||||
if(!playPackets.isEmpty()) {
|
||||
List<byte[]> ret = new ArrayList<>(playPackets);
|
||||
playPackets.clear();
|
||||
return ret;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int countAvailableReadData() {
|
||||
int total = 0;
|
||||
synchronized(playPackets) {
|
||||
for(int i = 0, l = playPackets.size(); i < l; ++i) {
|
||||
total += playPackets.get(i).length;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static void recievedPlayPacket(byte[] arg0) {
|
||||
synchronized(playPackets) {
|
||||
playPackets.add(arg0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writePlayPacket(byte[] pkt) {
|
||||
if(wsPlayClient == null || wsPlayClient.isClosed()) {
|
||||
networkLogger.error("Tried to send {} byte play packet while the socket was closed!", pkt.length);
|
||||
}else {
|
||||
wsPlayClient.send(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
public static IServerQuery sendServerQuery(String uri, String accept) {
|
||||
URI u;
|
||||
|
||||
try {
|
||||
u = new URI(uri);
|
||||
}catch(URISyntaxException ex) {
|
||||
networkLogger.error("Invalid server URI: {}", uri);
|
||||
playConnectState = EnumEaglerConnectionState.FAILED;
|
||||
URI uri = new URI(socketURI);
|
||||
return new DesktopWebSocketClient(uri);
|
||||
}catch(Throwable t) {
|
||||
logger.error("Could not open WebSocket to \"{}\"!", socketURI);
|
||||
logger.error(t);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new WebSocketServerQuery(accept, u);
|
||||
}
|
||||
|
||||
public static EnumServerRateLimit getRateLimit() {
|
||||
return serverRateLimit == null ? EnumServerRateLimit.OK : serverRateLimit;
|
||||
}
|
||||
|
||||
public static String getCurrentURI() {
|
||||
return currentURI;
|
||||
public static IWebSocketClient openWebSocketUnsafe(String socketURI) throws URISyntaxException {
|
||||
URI uri = new URI(socketURI);
|
||||
return new DesktopWebSocketClient(uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,13 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
|
||||
import static org.lwjgl.opengles.GLES30.*;
|
||||
import static org.lwjgl.opengles.ANGLEInstancedArrays.*;
|
||||
import static org.lwjgl.opengles.EXTInstancedArrays.*;
|
||||
import static org.lwjgl.opengles.EXTTextureStorage.*;
|
||||
import static org.lwjgl.opengles.OESVertexArrayObject.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengles.GLESCapabilities;
|
||||
|
||||
@ -26,10 +33,103 @@ import org.lwjgl.opengles.GLESCapabilities;
|
||||
*/
|
||||
public class PlatformOpenGL {
|
||||
|
||||
private static int glesVers = -1;
|
||||
|
||||
private static boolean hasANGLEInstancedArrays = false;
|
||||
private static boolean hasEXTColorBufferFloat = false;
|
||||
private static boolean hasEXTColorBufferHalfFloat = false;
|
||||
private static boolean hasEXTGPUShader5 = false;
|
||||
private static boolean hasEXTInstancedArrays = false;
|
||||
private static boolean hasEXTShaderTextureLOD = false;
|
||||
private static boolean hasEXTTextureStorage = false;
|
||||
private static boolean hasOESFBORenderMipmap = false;
|
||||
private static boolean hasOESGPUShader5 = false;
|
||||
private static boolean hasOESVertexArrayObject = false;
|
||||
private static boolean hasOESTextureFloat = false;
|
||||
private static boolean hasOESTextureFloatLinear = false;
|
||||
private static boolean hasOESTextureHalfFloat = false;
|
||||
private static boolean hasOESTextureHalfFloatLinear = false;
|
||||
private static boolean hasEXTTextureFilterAnisotropic = false;
|
||||
|
||||
private static boolean hasFBO16FSupport = false;
|
||||
private static boolean hasFBO32FSupport = false;
|
||||
private static boolean hasLinearHDR16FSupport = false;
|
||||
private static boolean hasLinearHDR32FSupport = false;
|
||||
|
||||
static void setCurrentContext(GLESCapabilities caps) {
|
||||
private static final int VAO_IMPL_NONE = -1;
|
||||
private static final int VAO_IMPL_CORE = 0;
|
||||
private static final int VAO_IMPL_OES = 1;
|
||||
private static int vertexArrayImpl = VAO_IMPL_NONE;
|
||||
|
||||
private static final int INSTANCE_IMPL_NONE = -1;
|
||||
private static final int INSTANCE_IMPL_CORE = 0;
|
||||
private static final int INSTANCE_IMPL_ANGLE = 1;
|
||||
private static final int INSTANCE_IMPL_EXT = 2;
|
||||
private static int instancingImpl = INSTANCE_IMPL_NONE;
|
||||
|
||||
private static final int TEX_STORAGE_IMPL_NONE = -1;
|
||||
private static final int TEX_STORAGE_IMPL_CORE = 0;
|
||||
private static final int TEX_STORAGE_IMPL_EXT = 1;
|
||||
private static int texStorageImpl = TEX_STORAGE_IMPL_NONE;
|
||||
|
||||
static void setCurrentContext(int glesVersIn, GLESCapabilities caps) {
|
||||
glesVers = glesVersIn;
|
||||
|
||||
hasANGLEInstancedArrays = glesVersIn == 200 && caps.GL_ANGLE_instanced_arrays;
|
||||
hasOESTextureFloat = glesVersIn == 200 && caps.GL_OES_texture_float;
|
||||
hasOESTextureFloatLinear = glesVersIn >= 300 && caps.GL_OES_texture_float_linear;
|
||||
hasOESTextureHalfFloat = glesVersIn == 200 && caps.GL_OES_texture_half_float;
|
||||
hasOESTextureHalfFloatLinear = glesVersIn == 200 && caps.GL_OES_texture_half_float_linear;
|
||||
hasEXTColorBufferFloat = (glesVersIn == 310 || glesVersIn == 300) && caps.GL_EXT_color_buffer_float;
|
||||
hasEXTColorBufferHalfFloat = !hasEXTColorBufferFloat
|
||||
&& (glesVersIn == 310 || glesVersIn == 300 || glesVersIn == 200) && caps.GL_EXT_color_buffer_half_float;
|
||||
hasEXTInstancedArrays = !hasANGLEInstancedArrays && glesVersIn == 200 && caps.GL_EXT_instanced_arrays;
|
||||
hasEXTShaderTextureLOD = glesVersIn == 200 && caps.GL_EXT_shader_texture_lod;
|
||||
hasEXTTextureStorage = glesVersIn == 200 && caps.GL_EXT_texture_storage;
|
||||
hasOESGPUShader5 = glesVersIn == 310 && caps.GL_OES_gpu_shader5;
|
||||
hasEXTGPUShader5 = !hasOESGPUShader5 && glesVersIn == 310 && caps.GL_EXT_gpu_shader5;
|
||||
hasOESFBORenderMipmap = glesVersIn == 200 && caps.GL_OES_fbo_render_mipmap;
|
||||
hasOESVertexArrayObject = glesVersIn == 200 && caps.GL_OES_vertex_array_object;
|
||||
hasLinearHDR32FSupport = caps.GL_OES_texture_float_linear;
|
||||
hasEXTTextureFilterAnisotropic = caps.GL_EXT_texture_filter_anisotropic;
|
||||
|
||||
hasFBO16FSupport = glesVersIn >= 320 || ((glesVersIn >= 300 || hasOESTextureFloat) && (hasEXTColorBufferFloat || hasEXTColorBufferHalfFloat));
|
||||
hasFBO32FSupport = glesVersIn >= 320 || ((glesVersIn >= 300 || hasOESTextureHalfFloat) && hasEXTColorBufferFloat);
|
||||
hasLinearHDR16FSupport = glesVersIn >= 300 || hasOESTextureHalfFloatLinear;
|
||||
hasLinearHDR32FSupport = glesVersIn >= 300 && hasOESTextureFloatLinear;
|
||||
|
||||
if(glesVersIn >= 300) {
|
||||
vertexArrayImpl = VAO_IMPL_CORE;
|
||||
instancingImpl = INSTANCE_IMPL_CORE;
|
||||
texStorageImpl = TEX_STORAGE_IMPL_CORE;
|
||||
}else if(glesVersIn == 200) {
|
||||
vertexArrayImpl = hasOESVertexArrayObject ? VAO_IMPL_OES : VAO_IMPL_NONE;
|
||||
instancingImpl = hasANGLEInstancedArrays ? INSTANCE_IMPL_ANGLE : (hasEXTInstancedArrays ? INSTANCE_IMPL_EXT : INSTANCE_IMPL_NONE);
|
||||
texStorageImpl = hasEXTTextureStorage ? TEX_STORAGE_IMPL_EXT : TEX_STORAGE_IMPL_NONE;
|
||||
}else {
|
||||
vertexArrayImpl = VAO_IMPL_NONE;
|
||||
instancingImpl = INSTANCE_IMPL_NONE;
|
||||
texStorageImpl = TEX_STORAGE_IMPL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public static final List<String> dumpActiveExtensions() {
|
||||
List<String> exts = new ArrayList<>();
|
||||
if(hasANGLEInstancedArrays) exts.add("ANGLE_instanced_arrays");
|
||||
if(hasEXTColorBufferFloat) exts.add("EXT_color_buffer_float");
|
||||
if(hasEXTColorBufferHalfFloat) exts.add("EXT_color_buffer_half_float");
|
||||
if(hasEXTGPUShader5) exts.add("EXT_gpu_shader5");
|
||||
if(hasEXTInstancedArrays) exts.add("EXT_instanced_arrays");
|
||||
if(hasEXTTextureStorage) exts.add("EXT_texture_storage");
|
||||
if(hasOESFBORenderMipmap) exts.add("OES_fbo_render_mipmap");
|
||||
if(hasOESGPUShader5) exts.add("OES_gpu_shader5");
|
||||
if(hasOESVertexArrayObject) exts.add("OES_vertex_array_object");
|
||||
if(hasOESTextureFloat) exts.add("OES_texture_float");
|
||||
if(hasOESTextureFloatLinear) exts.add("OES_texture_float_linear");
|
||||
if(hasOESTextureHalfFloat) exts.add("OES_texture_half_float");
|
||||
if(hasOESTextureHalfFloatLinear) exts.add("OES_texture_half_float_linear");
|
||||
if(hasEXTTextureFilterAnisotropic) exts.add("EXT_texture_filter_anisotropic");
|
||||
return exts;
|
||||
}
|
||||
|
||||
public static final void _wglEnable(int glEnum) {
|
||||
@ -89,17 +189,45 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final void _wglDrawBuffers(int buffer) {
|
||||
glDrawBuffers(buffer);
|
||||
if(glesVers == 200) {
|
||||
if(buffer != 0x8CE0) { // GL_COLOR_ATTACHMENT0
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}else {
|
||||
glDrawBuffers(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglDrawBuffers(int[] buffers) {
|
||||
glDrawBuffers(buffers);
|
||||
if(glesVers == 200) {
|
||||
if(buffers.length != 1 || buffers[0] != 0x8CE0) { // GL_COLOR_ATTACHMENT0
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}else {
|
||||
glDrawBuffers(buffers);
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglReadBuffer(int buffer) {
|
||||
glReadBuffer(buffer);
|
||||
}
|
||||
|
||||
public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer data) {
|
||||
nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
|
||||
}
|
||||
|
||||
public static final void _wglReadPixels_u16(int x, int y, int width, int height, int format, int type, ByteBuffer data) {
|
||||
nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
|
||||
}
|
||||
|
||||
public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, IntBuffer data) {
|
||||
nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
|
||||
}
|
||||
|
||||
public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, FloatBuffer data) {
|
||||
nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
|
||||
}
|
||||
|
||||
public static final void _wglPolygonOffset(float f1, float f2) {
|
||||
glPolygonOffset(f1, f2);
|
||||
}
|
||||
@ -117,7 +245,14 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final IBufferArrayGL _wglGenVertexArrays() {
|
||||
return new OpenGLObjects.BufferArrayGL(glGenVertexArrays());
|
||||
switch(vertexArrayImpl) {
|
||||
case VAO_IMPL_CORE:
|
||||
return new OpenGLObjects.BufferArrayGL(glGenVertexArrays());
|
||||
case VAO_IMPL_OES:
|
||||
return new OpenGLObjects.BufferArrayGL(glGenVertexArraysOES());
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final IProgramGL _wglCreateProgram() {
|
||||
@ -149,7 +284,17 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final void _wglDeleteVertexArrays(IBufferArrayGL obj) {
|
||||
glDeleteVertexArrays(((OpenGLObjects.BufferArrayGL) obj).ptr);
|
||||
int ptr = ((OpenGLObjects.BufferArrayGL) obj).ptr;
|
||||
switch(vertexArrayImpl) {
|
||||
case VAO_IMPL_CORE:
|
||||
glDeleteVertexArrays(ptr);
|
||||
break;
|
||||
case VAO_IMPL_OES:
|
||||
glDeleteVertexArraysOES(ptr);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglDeleteProgram(IProgramGL obj) {
|
||||
@ -211,7 +356,17 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final void _wglBindVertexArray(IBufferArrayGL obj) {
|
||||
glBindVertexArray(obj == null ? 0 : ((OpenGLObjects.BufferArrayGL) obj).ptr);
|
||||
int ptr = obj == null ? 0 : ((OpenGLObjects.BufferArrayGL) obj).ptr;
|
||||
switch(vertexArrayImpl) {
|
||||
case VAO_IMPL_CORE:
|
||||
glBindVertexArray(ptr);
|
||||
break;
|
||||
case VAO_IMPL_OES:
|
||||
glBindVertexArrayOES(ptr);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglEnableVertexAttribArray(int index) {
|
||||
@ -228,7 +383,19 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final void _wglVertexAttribDivisor(int index, int divisor) {
|
||||
glVertexAttribDivisor(index, divisor);
|
||||
switch(instancingImpl) {
|
||||
case INSTANCE_IMPL_CORE:
|
||||
glVertexAttribDivisor(index, divisor);
|
||||
break;
|
||||
case INSTANCE_IMPL_ANGLE:
|
||||
glVertexAttribDivisorANGLE(index, divisor);
|
||||
break;
|
||||
case INSTANCE_IMPL_EXT:
|
||||
glVertexAttribDivisorEXT(index, divisor);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglActiveTexture(int texture) {
|
||||
@ -313,7 +480,16 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final void _wglTexStorage2D(int target, int levels, int internalFormat, int w, int h) {
|
||||
glTexStorage2D(target, levels, internalFormat, w, h);
|
||||
switch(texStorageImpl) {
|
||||
case TEX_STORAGE_IMPL_CORE:
|
||||
glTexStorage2D(target, levels, internalFormat, w, h);
|
||||
break;
|
||||
case TEX_STORAGE_IMPL_EXT:
|
||||
glTexStorage2DEXT(target, levels, internalFormat, w, h);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglPixelStorei(int pname, int value) {
|
||||
@ -377,7 +553,19 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final void _wglDrawArraysInstanced(int mode, int first, int count, int instanced) {
|
||||
glDrawArraysInstanced(mode, first, count, instanced);
|
||||
switch(instancingImpl) {
|
||||
case INSTANCE_IMPL_CORE:
|
||||
glDrawArraysInstanced(mode, first, count, instanced);
|
||||
break;
|
||||
case INSTANCE_IMPL_ANGLE:
|
||||
glDrawArraysInstancedANGLE(mode, first, count, instanced);
|
||||
break;
|
||||
case INSTANCE_IMPL_EXT:
|
||||
glDrawArraysInstancedEXT(mode, first, count, instanced);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final void _wglDrawElements(int mode, int count, int type, int offset) {
|
||||
@ -385,7 +573,19 @@ public class PlatformOpenGL {
|
||||
}
|
||||
|
||||
public static final void _wglDrawElementsInstanced(int mode, int count, int type, int offset, int instanced) {
|
||||
glDrawElementsInstanced(mode, count, type, offset, instanced);
|
||||
switch(instancingImpl) {
|
||||
case INSTANCE_IMPL_CORE:
|
||||
glDrawElementsInstanced(mode, count, type, offset, instanced);
|
||||
break;
|
||||
case INSTANCE_IMPL_ANGLE:
|
||||
glDrawElementsInstancedANGLE(mode, count, type, offset, instanced);
|
||||
break;
|
||||
case INSTANCE_IMPL_EXT:
|
||||
glDrawElementsInstancedEXT(mode, count, type, offset, instanced);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final IUniformGL _wglGetUniformLocation(IProgramGL obj, String name) {
|
||||
@ -533,11 +733,79 @@ public class PlatformOpenGL {
|
||||
return glGetError();
|
||||
}
|
||||
|
||||
public static final boolean checkHDRFramebufferSupport(int bits) {
|
||||
return true;
|
||||
public static final int checkOpenGLESVersion() {
|
||||
return glesVers;
|
||||
}
|
||||
|
||||
public static final boolean checkEXTGPUShader5Capable() {
|
||||
return hasEXTGPUShader5;
|
||||
}
|
||||
|
||||
public static final boolean checkOESGPUShader5Capable() {
|
||||
return hasOESGPUShader5;
|
||||
}
|
||||
|
||||
public static final boolean checkFBORenderMipmapCapable() {
|
||||
return hasOESFBORenderMipmap;
|
||||
}
|
||||
|
||||
public static final boolean checkVAOCapable() {
|
||||
return vertexArrayImpl != VAO_IMPL_NONE;
|
||||
}
|
||||
|
||||
public static final boolean checkInstancingCapable() {
|
||||
return instancingImpl != INSTANCE_IMPL_NONE;
|
||||
}
|
||||
|
||||
public static final boolean checkTexStorageCapable() {
|
||||
return texStorageImpl != TEX_STORAGE_IMPL_NONE;
|
||||
}
|
||||
|
||||
public static final boolean checkTextureLODCapable() {
|
||||
return glesVers >= 300 || hasEXTShaderTextureLOD;
|
||||
}
|
||||
|
||||
public static final boolean checkNPOTCapable() {
|
||||
return glesVers >= 300;
|
||||
}
|
||||
|
||||
public static final boolean checkHDRFramebufferSupport(int bits) {
|
||||
switch(bits) {
|
||||
case 16:
|
||||
return hasFBO16FSupport;
|
||||
case 32:
|
||||
return hasFBO32FSupport;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean checkLinearHDRFilteringSupport(int bits) {
|
||||
switch(bits) {
|
||||
case 16:
|
||||
return hasLinearHDR16FSupport;
|
||||
case 32:
|
||||
return hasLinearHDR32FSupport;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// legacy
|
||||
public static final boolean checkLinearHDR32FSupport() {
|
||||
return hasLinearHDR32FSupport;
|
||||
}
|
||||
|
||||
public static final boolean checkAnisotropicFilteringSupport() {
|
||||
return hasEXTTextureFilterAnisotropic;
|
||||
}
|
||||
|
||||
public static final String[] getAllExtensions() {
|
||||
return glGetString(GL_EXTENSIONS).split(" ");
|
||||
}
|
||||
|
||||
public static final void enterVAOEmulationHook() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
@ -31,6 +33,7 @@ import org.lwjgl.opengles.GLDebugMessageKHRCallback;
|
||||
import org.lwjgl.opengles.GLDebugMessageKHRCallbackI;
|
||||
import org.lwjgl.opengles.GLES;
|
||||
import org.lwjgl.opengles.GLES30;
|
||||
import org.lwjgl.opengles.GLESCapabilities;
|
||||
import org.lwjgl.opengles.KHRDebug;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
@ -38,16 +41,19 @@ import org.lwjgl.system.jemalloc.JEmalloc;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerLWJGLAllocator;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.Filesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DesktopClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -74,7 +80,22 @@ public class PlatformRuntime {
|
||||
|
||||
public static void create() {
|
||||
logger.info("Starting Desktop Runtime...");
|
||||
PlatformFilesystem.initialize();
|
||||
|
||||
ByteBuffer endiannessTestBytes = allocateByteBuffer(4);
|
||||
try {
|
||||
endiannessTestBytes.asIntBuffer().put(0x6969420);
|
||||
if (((endiannessTestBytes.get(0) & 0xFF) | ((endiannessTestBytes.get(1) & 0xFF) << 8)
|
||||
| ((endiannessTestBytes.get(2) & 0xFF) << 16) | ((endiannessTestBytes.get(3) & 0xFF) << 24)) != 0x6969420) {
|
||||
throw new UnsupportedOperationException("Big endian CPU detected! (somehow)");
|
||||
}else {
|
||||
logger.info("Endianness: this CPU is little endian");
|
||||
}
|
||||
}finally {
|
||||
freeByteBuffer(endiannessTestBytes);
|
||||
}
|
||||
|
||||
IEaglerFilesystem resourcePackFilesystem = Filesystem.getHandleFor(getClientConfigAdapter().getResourcePacksDB());
|
||||
VFile2.setPrimaryFilesystem(resourcePackFilesystem);
|
||||
EaglerFolderResourcePack.setSupported(true);
|
||||
|
||||
if(requestedANGLEPlatform != EnumPlatformANGLE.DEFAULT) {
|
||||
@ -91,23 +112,54 @@ public class PlatformRuntime {
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
|
||||
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
|
||||
|
||||
|
||||
PointerBuffer buf = glfwGetMonitors();
|
||||
GLFWVidMode mon = glfwGetVideoMode(buf.get(0));
|
||||
|
||||
int windowWidth = mon.width() - 200;
|
||||
int windowHeight = mon.height() - 250;
|
||||
String title = "Eaglercraft Desktop Runtime";
|
||||
|
||||
int winX = (mon.width() - windowWidth) / 2;
|
||||
int winY = (mon.height() - windowHeight - 20) / 2;
|
||||
|
||||
windowHandle = glfwCreateWindow(windowWidth, windowHeight, "Eaglercraft Desktop Runtime", 0l, 0l);
|
||||
int myGLVersion = -1;
|
||||
if(requestedGLVersion >= 310 && windowHandle == 0) {
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||
windowHandle = glfwCreateWindow(windowWidth, windowHeight, title, 0l, 0l);
|
||||
if(windowHandle == 0l) {
|
||||
logger.error("Failed to create OpenGL ES 3.1 context!");
|
||||
}else {
|
||||
myGLVersion = 310;
|
||||
}
|
||||
}
|
||||
if(requestedGLVersion >= 300 && windowHandle == 0) {
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
windowHandle = glfwCreateWindow(windowWidth, windowHeight, title, 0l, 0l);
|
||||
if(windowHandle == 0l) {
|
||||
logger.error("Failed to create OpenGL ES 3.0 context!");
|
||||
}else {
|
||||
myGLVersion = 300;
|
||||
}
|
||||
}
|
||||
if(requestedGLVersion >= 200 && windowHandle == 0) {
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
windowHandle = glfwCreateWindow(windowWidth, windowHeight, title, 0l, 0l);
|
||||
if(windowHandle == 0l) {
|
||||
logger.error("Failed to create OpenGL ES 2.0 context!");
|
||||
}else {
|
||||
myGLVersion = 200;
|
||||
}
|
||||
}
|
||||
if(myGLVersion == -1) {
|
||||
throw new RuntimeException("Could not create a supported OpenGL ES context!");
|
||||
}
|
||||
|
||||
glfwSetWindowPos(windowHandle, winX, winY);
|
||||
|
||||
@ -171,13 +223,28 @@ public class PlatformRuntime {
|
||||
|
||||
EGL.createDisplayCapabilities(glfw_eglHandle, major[0], minor[0]);
|
||||
glfwMakeContextCurrent(windowHandle);
|
||||
PlatformOpenGL.setCurrentContext(GLES.createCapabilities());
|
||||
GLESCapabilities caps = GLES.createCapabilities();
|
||||
PlatformOpenGL.setCurrentContext(myGLVersion, caps);
|
||||
|
||||
logger.info("OpenGL Version: {}", (glVersion = GLES30.glGetString(GLES30.GL_VERSION)));
|
||||
logger.info("OpenGL Renderer: {}", (glRenderer = GLES30.glGetString(GLES30.GL_RENDERER)));
|
||||
|
||||
rendererANGLEPlatform = EnumPlatformANGLE.fromGLRendererString(glRenderer);
|
||||
|
||||
int realGLVersion = (glVersion != null && probablyGLES2(glVersion)) ? 200
|
||||
: (GLES30.glGetInteger(GLES30.GL_MAJOR_VERSION) * 100
|
||||
+ GLES30.glGetInteger(GLES30.GL_MINOR_VERSION) * 10);
|
||||
if(realGLVersion != myGLVersion) {
|
||||
logger.warn("Unexpected GLES verison resolved for requested {} context: {}", myGLVersion, realGLVersion);
|
||||
if(myGLVersion == 200) {
|
||||
logger.warn("Note: try adding the \"d3d9\" option if you are on windows trying to get GLES 2.0");
|
||||
}
|
||||
if(realGLVersion != 320 && realGLVersion != 310 && realGLVersion != 300 && realGLVersion != 200) {
|
||||
throw new RuntimeException("Unsupported OpenGL ES version detected: " + realGLVersion);
|
||||
}
|
||||
myGLVersion = realGLVersion;
|
||||
PlatformOpenGL.setCurrentContext(myGLVersion, caps);
|
||||
}
|
||||
|
||||
if(requestedANGLEPlatform != EnumPlatformANGLE.DEFAULT
|
||||
&& rendererANGLEPlatform != requestedANGLEPlatform) {
|
||||
logger.warn("Incorrect ANGLE Platform: {}", rendererANGLEPlatform.name);
|
||||
@ -187,6 +254,18 @@ public class PlatformRuntime {
|
||||
logger.info("ANGLE Platform: {}", rendererANGLEPlatform.name);
|
||||
}
|
||||
|
||||
List<String> exts = PlatformOpenGL.dumpActiveExtensions();
|
||||
if(exts.isEmpty()) {
|
||||
logger.info("Unlocked the following OpenGL ES extensions: (NONE)");
|
||||
}else {
|
||||
Collections.sort(exts);
|
||||
logger.info("Unlocked the following OpenGL ES extensions:");
|
||||
for(int i = 0, l = exts.size(); i < l; ++i) {
|
||||
logger.info(" - " + exts.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
glfwSwapInterval(0);
|
||||
|
||||
KHRDebug.glDebugMessageCallbackKHR(new GLDebugMessageKHRCallbackI() {
|
||||
@ -245,13 +324,20 @@ public class PlatformRuntime {
|
||||
|
||||
public static void destroy() {
|
||||
PlatformAudio.platformShutdown();
|
||||
PlatformFilesystem.platformShutdown();
|
||||
Filesystem.closeAllHandles();
|
||||
ServerPlatformSingleplayer.platformShutdown();
|
||||
GLES.destroy();
|
||||
EGL.destroy();
|
||||
glfwDestroyWindow(windowHandle);
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
private static boolean probablyGLES2(String glVersion) {
|
||||
if(glVersion == null) return false;
|
||||
glVersion = glVersion.toLowerCase();
|
||||
return glVersion.contains("opengl es 2.0") || glVersion.contains("ES 2.0");
|
||||
}
|
||||
|
||||
public static EnumPlatformType getPlatformType() {
|
||||
return EnumPlatformType.DESKTOP;
|
||||
}
|
||||
@ -274,11 +360,16 @@ public class PlatformRuntime {
|
||||
}
|
||||
|
||||
private static EnumPlatformANGLE requestedANGLEPlatform = EnumPlatformANGLE.DEFAULT;
|
||||
private static int requestedGLVersion = 300;
|
||||
|
||||
public static void requestANGLE(EnumPlatformANGLE plaf) {
|
||||
requestedANGLEPlatform = plaf;
|
||||
}
|
||||
|
||||
public static void requestGL(int i) {
|
||||
requestedGLVersion = i;
|
||||
}
|
||||
|
||||
public static EnumPlatformANGLE getPlatformANGLE() {
|
||||
return rendererANGLEPlatform;
|
||||
}
|
||||
@ -499,18 +590,6 @@ public class PlatformRuntime {
|
||||
return DesktopClientConfigAdapter.instance;
|
||||
}
|
||||
|
||||
public static String getRecText() {
|
||||
return "recording.unsupported";
|
||||
}
|
||||
|
||||
public static boolean recSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void toggleRec() {
|
||||
//
|
||||
}
|
||||
|
||||
private static final Random seedProvider = new Random();
|
||||
|
||||
public static long randomSeed() {
|
||||
@ -530,4 +609,25 @@ public class PlatformRuntime {
|
||||
public static long getWindowHandle() {
|
||||
return windowHandle;
|
||||
}
|
||||
|
||||
public static long steadyTimeMillis() {
|
||||
return System.nanoTime() / 1000000l;
|
||||
}
|
||||
|
||||
public static long nanoTime() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
public static void postCreate() {
|
||||
|
||||
}
|
||||
|
||||
public static void setDisplayBootMenuNextRefresh(boolean en) {
|
||||
|
||||
}
|
||||
|
||||
public static void immediateContinue() {
|
||||
// nope
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
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;
|
||||
import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -18,17 +17,43 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformBufferFunctions {
|
||||
public class PlatformScreenRecord {
|
||||
|
||||
public static void put(ByteBuffer newBuffer, ByteBuffer flip) {
|
||||
newBuffer.put(flip);
|
||||
public static boolean isSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void put(IntBuffer intBuffer, int index, int[] data) {
|
||||
int p = intBuffer.position();
|
||||
intBuffer.position(index);
|
||||
intBuffer.put(data);
|
||||
intBuffer.position(p);
|
||||
public static boolean isCodecSupported(EnumScreenRecordingCodec codec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static void setGameVolume(float volume) {
|
||||
|
||||
}
|
||||
|
||||
public static void setMicrophoneVolume(float volume) {
|
||||
|
||||
}
|
||||
|
||||
public static void startRecording(ScreenRecordParameters params) {
|
||||
|
||||
}
|
||||
|
||||
public static void endRecording() {
|
||||
|
||||
}
|
||||
|
||||
public static boolean isRecording() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isMicVolumeLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isVSyncLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateProgressStruct;
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateResultObj;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
@ -46,6 +47,15 @@ public class PlatformUpdateSvc {
|
||||
return dummyStruct;
|
||||
}
|
||||
|
||||
public static UpdateResultObj getUpdateResult() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void installSignedClient(UpdateCertificate clientCert, byte[] clientPayload, boolean setDefault,
|
||||
boolean setTimeout) {
|
||||
|
||||
}
|
||||
|
||||
public static void quine(String filename, byte[] cert, byte[] data, String date) {
|
||||
|
||||
}
|
||||
|
@ -4,20 +4,22 @@ import dev.onvoid.webrtc.*;
|
||||
import dev.onvoid.webrtc.internal.NativeLoader;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANPeerEvent;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayLoggerImpl;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryImpl;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryRateLimitDummy;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerRateLimitTracker;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketImpl;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketRateLimitDummy;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.*;
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryImpl;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryRateLimitDummy;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONWriter;
|
||||
@ -25,10 +27,7 @@ import org.json.JSONWriter;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
@ -52,10 +51,25 @@ public class PlatformWebRTC {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformWebRTC");
|
||||
|
||||
private static final RelayLoggerImpl loggerImpl = new RelayLoggerImpl(LogManager.getLogger("RelayPacket"));
|
||||
|
||||
private static final Object lock1 = new Object();
|
||||
private static final Object lock2 = new Object();
|
||||
private static final Object lock3 = new Object();
|
||||
private static final Object lock4 = new Object();
|
||||
|
||||
private static final List<ScheduledRunnable> scheduledRunnables = new LinkedList<>();
|
||||
|
||||
private static class ScheduledRunnable {
|
||||
|
||||
private final long runAt;
|
||||
private final Runnable runnable;
|
||||
|
||||
private ScheduledRunnable(long runAt, Runnable runnable) {
|
||||
this.runAt = runAt;
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static PeerConnectionFactory pcFactory;
|
||||
|
||||
@ -72,7 +86,8 @@ public class PlatformWebRTC {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> pcFactory.dispose()));
|
||||
supported = true;
|
||||
} catch (Exception e) {
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
logger.error("Failed to load WebRTC native library!");
|
||||
logger.error(e);
|
||||
supported = false;
|
||||
}
|
||||
}
|
||||
@ -81,6 +96,46 @@ public class PlatformWebRTC {
|
||||
|
||||
private static final Map<String, RTCDataChannel> fuckTeaVM = new HashMap<>();
|
||||
|
||||
private static final Comparator<ScheduledRunnable> sortTasks = (r1, r2) -> {
|
||||
return (int)(r1.runAt - r2.runAt);
|
||||
};
|
||||
|
||||
public static void runScheduledTasks() {
|
||||
List<ScheduledRunnable> toRun = null;
|
||||
synchronized(scheduledRunnables) {
|
||||
if(scheduledRunnables.isEmpty()) return;
|
||||
long millis = PlatformRuntime.steadyTimeMillis();
|
||||
Iterator<ScheduledRunnable> itr = scheduledRunnables.iterator();
|
||||
while(itr.hasNext()) {
|
||||
ScheduledRunnable r = itr.next();
|
||||
if(r.runAt < millis) {
|
||||
itr.remove();
|
||||
if(toRun == null) {
|
||||
toRun = new ArrayList<>(1);
|
||||
}
|
||||
toRun.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(toRun != null) {
|
||||
Collections.sort(toRun, sortTasks);
|
||||
for(int i = 0, l = toRun.size(); i < l; ++i) {
|
||||
try {
|
||||
toRun.get(i).runnable.run();
|
||||
}catch(Throwable t) {
|
||||
logger.error("Caught exception running scheduled WebRTC task!");
|
||||
logger.error(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void scheduleTask(long runAfter, Runnable runnable) {
|
||||
synchronized(scheduledRunnables) {
|
||||
scheduledRunnables.add(new ScheduledRunnable(PlatformRuntime.steadyTimeMillis() + runAfter, runnable));
|
||||
}
|
||||
}
|
||||
|
||||
public static class LANClient {
|
||||
public static final byte READYSTATE_INIT_FAILED = -2;
|
||||
public static final byte READYSTATE_FAILED = -1;
|
||||
@ -123,15 +178,14 @@ public class PlatformWebRTC {
|
||||
synchronized (lock1) {
|
||||
if (iceCandidate.sdp != null && !iceCandidate.sdp.isEmpty()) {
|
||||
if (iceCandidates.isEmpty()) {
|
||||
new Thread(() -> {
|
||||
EagUtils.sleep(3000);
|
||||
scheduleTask(3000l, () -> {
|
||||
synchronized (lock1) {
|
||||
if (peerConnection != null && peerConnection.getConnectionState() != RTCPeerConnectionState.DISCONNECTED) {
|
||||
clientICECandidate = JSONWriter.valueToString(iceCandidates);
|
||||
iceCandidates.clear();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
Map<String, String> m = new HashMap<>();
|
||||
m.put("sdpMLineIndex", "" + iceCandidate.sdpMLineIndex);
|
||||
@ -203,7 +257,7 @@ public class PlatformWebRTC {
|
||||
@Override
|
||||
public void onStateChange() {
|
||||
if (dataChannel != null && dataChannel.getState() == RTCDataChannelState.OPEN) {
|
||||
new Thread(() -> {
|
||||
scheduleTask(-1l, () -> {
|
||||
while (true) {
|
||||
synchronized (lock1) {
|
||||
if (iceCandidates.isEmpty()) {
|
||||
@ -216,7 +270,7 @@ public class PlatformWebRTC {
|
||||
clientDataChannelClosed = false;
|
||||
clientDataChannelOpen = true;
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,8 +540,7 @@ public class PlatformWebRTC {
|
||||
synchronized (lock3) {
|
||||
if (iceCandidate.sdp != null && !iceCandidate.sdp.isEmpty()) {
|
||||
if (iceCandidates.isEmpty()) {
|
||||
new Thread(() -> {
|
||||
EagUtils.sleep(3000);
|
||||
scheduleTask(3000l, () -> {
|
||||
synchronized (lock3) {
|
||||
if (peerConnection[0] != null && peerConnection[0].getConnectionState() != RTCPeerConnectionState.DISCONNECTED) {
|
||||
LANPeerEvent.LANPeerICECandidateEvent e = new LANPeerEvent.LANPeerICECandidateEvent(peerId, JSONWriter.valueToString(iceCandidates));
|
||||
@ -497,7 +550,7 @@ public class PlatformWebRTC {
|
||||
iceCandidates.clear();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
Map<String, String> m = new HashMap<>();
|
||||
m.put("sdpMLineIndex", "" + iceCandidate.sdpMLineIndex);
|
||||
@ -509,7 +562,7 @@ public class PlatformWebRTC {
|
||||
|
||||
@Override
|
||||
public void onDataChannel(RTCDataChannel dataChannel) {
|
||||
new Thread(() -> {
|
||||
scheduleTask(-1l, () -> {
|
||||
while (true) {
|
||||
synchronized (lock3) {
|
||||
if (iceCandidates.isEmpty()) {
|
||||
@ -547,7 +600,7 @@ public class PlatformWebRTC {
|
||||
}
|
||||
}
|
||||
});
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -625,795 +678,27 @@ public class PlatformWebRTC {
|
||||
return peerList.size();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<String,Long> relayQueryLimited = new HashMap<>();
|
||||
private static final Map<String,Long> relayQueryBlocked = new HashMap<>();
|
||||
|
||||
private static class RelayQueryImpl implements RelayQuery {
|
||||
|
||||
private final WebSocketClient sock;
|
||||
private final String uri;
|
||||
|
||||
private boolean open;
|
||||
private boolean failed;
|
||||
|
||||
private boolean hasRecievedAnyData = false;
|
||||
|
||||
private int vers = -1;
|
||||
private String comment = "<no comment>";
|
||||
private String brand = "<no brand>";
|
||||
|
||||
private long connectionOpenedAt;
|
||||
private long connectionPingStart = -1;
|
||||
private long connectionPingTimer = -1;
|
||||
|
||||
private RateLimit rateLimitStatus = RateLimit.NONE;
|
||||
|
||||
private VersionMismatch versError = VersionMismatch.UNKNOWN;
|
||||
|
||||
private RelayQueryImpl(String uri) {
|
||||
this.uri = uri;
|
||||
WebSocketClient s;
|
||||
try {
|
||||
connectionOpenedAt = System.currentTimeMillis();
|
||||
s = new WebSocketClient(new URI(uri)) {
|
||||
@Override
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
try {
|
||||
connectionPingStart = System.currentTimeMillis();
|
||||
sock.send(IPacket.writePacket(new IPacket00Handshake(0x03, RelayManager.preferredRelayVersion, "")));
|
||||
} catch (IOException e) {
|
||||
logger.error(e.toString());
|
||||
sock.close();
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String s) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer bb) {
|
||||
if(bb != null) {
|
||||
hasRecievedAnyData = true;
|
||||
byte[] arr = new byte[bb.remaining()];
|
||||
bb.get(arr);
|
||||
if(arr.length == 2 && arr[0] == (byte)0xFC) {
|
||||
long millis = System.currentTimeMillis();
|
||||
if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
|
||||
rateLimitStatus = RateLimit.BLOCKED;
|
||||
relayQueryLimited.put(RelayQueryImpl.this.uri, millis);
|
||||
}else if(arr[1] == (byte)0x02) {
|
||||
rateLimitStatus = RateLimit.NOW_LOCKED;
|
||||
relayQueryLimited.put(RelayQueryImpl.this.uri, millis);
|
||||
relayQueryBlocked.put(RelayQueryImpl.this.uri, millis);
|
||||
}else {
|
||||
rateLimitStatus = RateLimit.LOCKED;
|
||||
relayQueryBlocked.put(RelayQueryImpl.this.uri, millis);
|
||||
}
|
||||
failed = true;
|
||||
open = false;
|
||||
sock.close();
|
||||
}else {
|
||||
if(open) {
|
||||
try {
|
||||
IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
|
||||
if(pkt instanceof IPacket69Pong) {
|
||||
IPacket69Pong ipkt = (IPacket69Pong)pkt;
|
||||
versError = VersionMismatch.COMPATIBLE;
|
||||
if(connectionPingTimer == -1) {
|
||||
connectionPingTimer = System.currentTimeMillis() - connectionPingStart;
|
||||
}
|
||||
vers = ipkt.protcolVersion;
|
||||
comment = ipkt.comment;
|
||||
brand = ipkt.brand;
|
||||
open = false;
|
||||
failed = false;
|
||||
sock.close();
|
||||
}else if(pkt instanceof IPacket70SpecialUpdate) {
|
||||
IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
|
||||
if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
|
||||
UpdateService.addCertificateToSet(ipkt.updatePacket);
|
||||
}
|
||||
}else if(pkt instanceof IPacketFFErrorCode) {
|
||||
IPacketFFErrorCode ipkt = (IPacketFFErrorCode)pkt;
|
||||
if(ipkt.code == IPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
|
||||
String s1 = ipkt.desc.toLowerCase();
|
||||
if(s1.contains("outdated client") || s1.contains("client outdated")) {
|
||||
versError = VersionMismatch.CLIENT_OUTDATED;
|
||||
}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
|
||||
s1.contains("outdated relay") || s1.contains("server relay")) {
|
||||
versError = VersionMismatch.RELAY_OUTDATED;
|
||||
}else {
|
||||
versError = VersionMismatch.UNKNOWN;
|
||||
}
|
||||
}
|
||||
logger.error("{}\": Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
|
||||
open = false;
|
||||
failed = true;
|
||||
sock.close();
|
||||
}else {
|
||||
throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Relay Query Error: {}", e.toString());
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
open = false;
|
||||
failed = true;
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
open = false;
|
||||
if(!hasRecievedAnyData) {
|
||||
failed = true;
|
||||
Long l = relayQueryBlocked.get(uri);
|
||||
if(l != null) {
|
||||
if(System.currentTimeMillis() - l.longValue() < 400000l) {
|
||||
rateLimitStatus = RateLimit.LOCKED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
l = relayQueryLimited.get(uri);
|
||||
if(l != null) {
|
||||
if(System.currentTimeMillis() - l.longValue() < 900000l) {
|
||||
rateLimitStatus = RateLimit.BLOCKED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
}
|
||||
};
|
||||
s.connect();
|
||||
open = true;
|
||||
failed = false;
|
||||
}catch(Throwable t) {
|
||||
connectionOpenedAt = 0l;
|
||||
sock = null;
|
||||
open = false;
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
sock = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryFailed() {
|
||||
return failed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RateLimit isQueryRateLimit() {
|
||||
return rateLimitStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(sock != null && open) {
|
||||
sock.close();
|
||||
}
|
||||
open = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return vers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPing() {
|
||||
return connectionPingTimer < 1 ? 1 : connectionPingTimer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VersionMismatch getCompatible() {
|
||||
return versError;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class RelayQueryRatelimitDummy implements RelayQuery {
|
||||
|
||||
private final RateLimit type;
|
||||
|
||||
private RelayQueryRatelimitDummy(RateLimit type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryOpen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryFailed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RateLimit isQueryRateLimit() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return RelayManager.preferredRelayVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return "this query was rate limited";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBrand() {
|
||||
return "lax1dude";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPing() {
|
||||
return 0l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VersionMismatch getCompatible() {
|
||||
return VersionMismatch.COMPATIBLE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static RelayQuery openRelayQuery(String addr) {
|
||||
long millis = System.currentTimeMillis();
|
||||
|
||||
Long l = relayQueryBlocked.get(addr);
|
||||
if(l != null && millis - l.longValue() < 60000l) {
|
||||
return new RelayQueryRatelimitDummy(RelayQuery.RateLimit.LOCKED);
|
||||
RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
|
||||
if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
|
||||
return new RelayQueryRateLimitDummy(limit);
|
||||
}
|
||||
|
||||
l = relayQueryLimited.get(addr);
|
||||
if(l != null && millis - l.longValue() < 10000l) {
|
||||
return new RelayQueryRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
|
||||
}
|
||||
|
||||
return new RelayQueryImpl(addr);
|
||||
}
|
||||
|
||||
private static class RelayWorldsQueryImpl implements RelayWorldsQuery {
|
||||
|
||||
private final WebSocketClient sock;
|
||||
private final String uri;
|
||||
|
||||
private boolean open;
|
||||
private boolean failed;
|
||||
|
||||
private boolean hasRecievedAnyData = false;
|
||||
private RelayQuery.RateLimit rateLimitStatus = RelayQuery.RateLimit.NONE;
|
||||
|
||||
private RelayQuery.VersionMismatch versError = RelayQuery.VersionMismatch.UNKNOWN;
|
||||
|
||||
private List<IPacket07LocalWorlds.LocalWorld> worlds = null;
|
||||
|
||||
private RelayWorldsQueryImpl(String uri) {
|
||||
this.uri = uri;
|
||||
WebSocketClient s;
|
||||
try {
|
||||
s = new WebSocketClient(new URI(uri)) {
|
||||
@Override
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
try {
|
||||
sock.send(IPacket.writePacket(new IPacket00Handshake(0x04, RelayManager.preferredRelayVersion, "")));
|
||||
} catch (IOException e) {
|
||||
logger.error(e.toString());
|
||||
sock.close();
|
||||
open = false;
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String s) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer bb) {
|
||||
if(bb != null) {
|
||||
hasRecievedAnyData = true;
|
||||
byte[] arr = new byte[bb.remaining()];
|
||||
bb.get(arr);
|
||||
if(arr.length == 2 && arr[0] == (byte)0xFC) {
|
||||
long millis = System.currentTimeMillis();
|
||||
if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
|
||||
rateLimitStatus = RelayQuery.RateLimit.BLOCKED;
|
||||
relayQueryLimited.put(RelayWorldsQueryImpl.this.uri, millis);
|
||||
}else if(arr[1] == (byte)0x02) {
|
||||
rateLimitStatus = RelayQuery.RateLimit.NOW_LOCKED;
|
||||
relayQueryLimited.put(RelayWorldsQueryImpl.this.uri, millis);
|
||||
relayQueryBlocked.put(RelayWorldsQueryImpl.this.uri, millis);
|
||||
}else {
|
||||
rateLimitStatus = RelayQuery.RateLimit.LOCKED;
|
||||
relayQueryBlocked.put(RelayWorldsQueryImpl.this.uri, millis);
|
||||
}
|
||||
open = false;
|
||||
failed = true;
|
||||
sock.close();
|
||||
}else {
|
||||
if(open) {
|
||||
try {
|
||||
IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
|
||||
if(pkt instanceof IPacket07LocalWorlds) {
|
||||
worlds = ((IPacket07LocalWorlds)pkt).worldsList;
|
||||
sock.close();
|
||||
open = false;
|
||||
failed = false;
|
||||
}else if(pkt instanceof IPacket70SpecialUpdate) {
|
||||
IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
|
||||
if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
|
||||
UpdateService.addCertificateToSet(ipkt.updatePacket);
|
||||
}
|
||||
}else if(pkt instanceof IPacketFFErrorCode) {
|
||||
IPacketFFErrorCode ipkt = (IPacketFFErrorCode)pkt;
|
||||
if(ipkt.code == IPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
|
||||
String s1 = ipkt.desc.toLowerCase();
|
||||
if(s1.contains("outdated client") || s1.contains("client outdated")) {
|
||||
versError = RelayQuery.VersionMismatch.CLIENT_OUTDATED;
|
||||
}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
|
||||
s1.contains("outdated relay") || s1.contains("server relay")) {
|
||||
versError = RelayQuery.VersionMismatch.RELAY_OUTDATED;
|
||||
}else {
|
||||
versError = RelayQuery.VersionMismatch.UNKNOWN;
|
||||
}
|
||||
}
|
||||
logger.error("{}: Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
|
||||
open = false;
|
||||
failed = true;
|
||||
sock.close();
|
||||
}else {
|
||||
throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Relay World Query Error: {}", e.toString());
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
open = false;
|
||||
failed = true;
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
open = false;
|
||||
if(!hasRecievedAnyData) {
|
||||
failed = true;
|
||||
Long l = relayQueryBlocked.get(uri);
|
||||
if(l != null) {
|
||||
if(System.currentTimeMillis() - l.longValue() < 400000l) {
|
||||
rateLimitStatus = RelayQuery.RateLimit.LOCKED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
l = relayQueryLimited.get(uri);
|
||||
if(l != null) {
|
||||
if(System.currentTimeMillis() - l.longValue() < 900000l) {
|
||||
rateLimitStatus = RelayQuery.RateLimit.BLOCKED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
}
|
||||
};
|
||||
s.connect();
|
||||
open = true;
|
||||
failed = false;
|
||||
}catch(Throwable t) {
|
||||
sock = null;
|
||||
open = false;
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
sock = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryFailed() {
|
||||
return failed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelayQuery.RateLimit isQueryRateLimit() {
|
||||
return rateLimitStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(open && sock != null) {
|
||||
sock.close();
|
||||
}
|
||||
open = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IPacket07LocalWorlds.LocalWorld> getWorlds() {
|
||||
return worlds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelayQuery.VersionMismatch getCompatible() {
|
||||
return versError;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class RelayWorldsQueryRatelimitDummy implements RelayWorldsQuery {
|
||||
|
||||
private final RelayQuery.RateLimit rateLimit;
|
||||
|
||||
private RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit rateLimit) {
|
||||
this.rateLimit = rateLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryOpen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryFailed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelayQuery.RateLimit isQueryRateLimit() {
|
||||
return rateLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IPacket07LocalWorlds.LocalWorld> getWorlds() {
|
||||
return new ArrayList(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelayQuery.VersionMismatch getCompatible() {
|
||||
return RelayQuery.VersionMismatch.COMPATIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
public static RelayWorldsQuery openRelayWorldsQuery(String addr) {
|
||||
long millis = System.currentTimeMillis();
|
||||
|
||||
Long l = relayQueryBlocked.get(addr);
|
||||
if(l != null && millis - l.longValue() < 60000l) {
|
||||
return new RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit.LOCKED);
|
||||
RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
|
||||
if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
|
||||
return new RelayWorldsQueryRateLimitDummy(limit);
|
||||
}
|
||||
|
||||
l = relayQueryLimited.get(addr);
|
||||
if(l != null && millis - l.longValue() < 10000l) {
|
||||
return new RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
|
||||
}
|
||||
|
||||
return new RelayWorldsQueryImpl(addr);
|
||||
}
|
||||
|
||||
private static class RelayServerSocketImpl implements RelayServerSocket {
|
||||
|
||||
private final WebSocketClient sock;
|
||||
private final String uri;
|
||||
|
||||
private boolean open;
|
||||
private boolean closed;
|
||||
private boolean failed;
|
||||
|
||||
private boolean hasRecievedAnyData;
|
||||
|
||||
private final List<Throwable> exceptions = new LinkedList();
|
||||
private final List<IPacket> packets = new LinkedList();
|
||||
|
||||
private RelayServerSocketImpl(String uri, int timeout) {
|
||||
this.uri = uri;
|
||||
WebSocketClient s;
|
||||
try {
|
||||
s = new WebSocketClient(new URI(uri)) {
|
||||
@Override
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
synchronized (lock4) {
|
||||
open = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String s) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer bb) {
|
||||
if(bb != null) {
|
||||
hasRecievedAnyData = true;
|
||||
try {
|
||||
byte[] arr = new byte[bb.remaining()];
|
||||
bb.get(arr);
|
||||
IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
|
||||
if(pkt instanceof IPacket70SpecialUpdate) {
|
||||
IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
|
||||
if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
|
||||
UpdateService.addCertificateToSet(ipkt.updatePacket);
|
||||
}
|
||||
}else {
|
||||
packets.add(pkt);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
exceptions.add(e);
|
||||
logger.error("Relay Socket Error: {}", e.toString());
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
synchronized (lock4) {
|
||||
open = false;
|
||||
failed = true;
|
||||
}
|
||||
closed = true;
|
||||
synchronized (lock4) {
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
if (!hasRecievedAnyData) {
|
||||
failed = true;
|
||||
}
|
||||
synchronized (lock4) {
|
||||
open = false;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
}
|
||||
};
|
||||
s.connect();
|
||||
synchronized (lock4) {
|
||||
open = false;
|
||||
closed = false;
|
||||
}
|
||||
failed = false;
|
||||
}catch(Throwable t) {
|
||||
exceptions.add(t);
|
||||
synchronized (lock4) {
|
||||
sock = null;
|
||||
open = false;
|
||||
closed = true;
|
||||
}
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
synchronized (lock4) {
|
||||
sock = s;
|
||||
}
|
||||
new Thread(() -> {
|
||||
EagUtils.sleep(timeout);
|
||||
synchronized (lock4) {
|
||||
if (!open && !closed) {
|
||||
closed = true;
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
synchronized (lock4) {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(open && sock != null) {
|
||||
synchronized (lock4) {
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
synchronized (lock4) {
|
||||
open = false;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFailed() {
|
||||
return failed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getException() {
|
||||
if(!exceptions.isEmpty()) {
|
||||
return exceptions.remove(0);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(IPacket pkt) {
|
||||
try {
|
||||
sock.send(IPacket.writePacket(pkt));
|
||||
} catch (Throwable e) {
|
||||
logger.error("Relay connection error: {}", e.toString());
|
||||
EagRuntime.debugPrintStackTrace(e);
|
||||
exceptions.add(e);
|
||||
failed = true;
|
||||
synchronized (lock4) {
|
||||
open = false;
|
||||
closed = true;
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket readPacket() {
|
||||
if(!packets.isEmpty()) {
|
||||
return packets.remove(0);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket nextPacket() {
|
||||
if(!packets.isEmpty()) {
|
||||
return packets.get(0);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelayQuery.RateLimit getRatelimitHistory() {
|
||||
if(relayQueryBlocked.containsKey(uri)) {
|
||||
return RelayQuery.RateLimit.LOCKED;
|
||||
}
|
||||
if(relayQueryLimited.containsKey(uri)) {
|
||||
return RelayQuery.RateLimit.BLOCKED;
|
||||
}
|
||||
return RelayQuery.RateLimit.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURI() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class RelayServerSocketRatelimitDummy implements RelayServerSocket {
|
||||
|
||||
private final RelayQuery.RateLimit limit;
|
||||
|
||||
private RelayServerSocketRatelimitDummy(RelayQuery.RateLimit limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFailed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getException() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(IPacket pkt) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket readPacket() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPacket nextPacket() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelayQuery.RateLimit getRatelimitHistory() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURI() {
|
||||
return "<disconnected>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static RelayServerSocket openRelayConnection(String addr, int timeout) {
|
||||
long millis = System.currentTimeMillis();
|
||||
|
||||
Long l = relayQueryBlocked.get(addr);
|
||||
if(l != null && millis - l.longValue() < 60000l) {
|
||||
return new RelayServerSocketRatelimitDummy(RelayQuery.RateLimit.LOCKED);
|
||||
RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
|
||||
if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
|
||||
return new RelayServerSocketRateLimitDummy(limit);
|
||||
}
|
||||
|
||||
l = relayQueryLimited.get(addr);
|
||||
if(l != null && millis - l.longValue() < 10000l) {
|
||||
return new RelayServerSocketRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
|
||||
}
|
||||
|
||||
return new RelayServerSocketImpl(addr, timeout);
|
||||
}
|
||||
|
||||
@ -1453,7 +738,7 @@ public class PlatformWebRTC {
|
||||
public static List<byte[]> clientLANReadAllPacket() {
|
||||
synchronized(clientLANPacketBuffer) {
|
||||
if(!clientLANPacketBuffer.isEmpty()) {
|
||||
List<byte[]> ret = new ArrayList(clientLANPacketBuffer);
|
||||
List<byte[]> ret = new ArrayList<>(clientLANPacketBuffer);
|
||||
clientLANPacketBuffer.clear();
|
||||
return ret;
|
||||
}else {
|
||||
|
@ -0,0 +1,93 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.FallbackWebViewServer;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformWebView {
|
||||
|
||||
private static FallbackWebViewServer fallbackServer = null;
|
||||
private static IPacketSendCallback packetCallback = null;
|
||||
|
||||
public static boolean supported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isShowing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void beginShowing(WebViewOptions options, int x, int y, int w, int h) {
|
||||
|
||||
}
|
||||
|
||||
public static void resize(int x, int y, int w, int h) {
|
||||
|
||||
}
|
||||
|
||||
public static void endShowing() {
|
||||
|
||||
}
|
||||
|
||||
public static boolean fallbackSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void launchFallback(WebViewOptions options) {
|
||||
fallbackServer = new FallbackWebViewServer(options);
|
||||
fallbackServer.setPacketSendCallback(packetCallback);
|
||||
fallbackServer.start();
|
||||
}
|
||||
|
||||
public static boolean fallbackRunning() {
|
||||
return fallbackServer != null && !fallbackServer.isDead();
|
||||
}
|
||||
|
||||
public static String getFallbackURL() {
|
||||
return fallbackServer != null ? fallbackServer.getURL() : null;
|
||||
}
|
||||
|
||||
public static void endFallbackServer() {
|
||||
if(fallbackServer != null && !fallbackServer.isDead()) {
|
||||
fallbackServer.killServer();
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleMessageFromServer(SPacketWebViewMessageV4EAG packet) {
|
||||
if(fallbackServer != null && !fallbackServer.isDead()) {
|
||||
fallbackServer.handleMessageFromServer(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setPacketSendCallback(IPacketSendCallback callback) {
|
||||
packetCallback = callback;
|
||||
if(fallbackServer != null) {
|
||||
fallbackServer.setPacketSendCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTick() {
|
||||
if(fallbackServer != null) {
|
||||
fallbackServer.runTick();
|
||||
if(fallbackServer.isDead()) {
|
||||
fallbackServer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.drafts.Draft;
|
||||
import org.java_websocket.drafts.Draft_6455;
|
||||
import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
class WebSocketServerQuery extends WebSocketClient implements IServerQuery {
|
||||
|
||||
private static final Draft perMessageDeflateDraft = new Draft_6455(new PerMessageDeflateExtension());
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("WebSocketQuery");
|
||||
|
||||
private final List<QueryResponse> queryResponses = new LinkedList();
|
||||
private final List<byte[]> queryResponsesBytes = new LinkedList();
|
||||
private final String type;
|
||||
private boolean open = true;
|
||||
private boolean alive = false;
|
||||
private long pingStart = -1l;
|
||||
private long pingTimer = -1l;
|
||||
private EnumServerRateLimit rateLimit = EnumServerRateLimit.OK;
|
||||
|
||||
WebSocketServerQuery(String type, URI serverUri) {
|
||||
super(serverUri, perMessageDeflateDraft);
|
||||
this.type = type;
|
||||
this.setConnectionLostTimeout(5);
|
||||
this.setTcpNoDelay(true);
|
||||
this.connect();
|
||||
}
|
||||
|
||||
@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 EnumServerRateLimit getRateLimit() {
|
||||
return rateLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int arg0, String arg1, boolean arg2) {
|
||||
open = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception arg0) {
|
||||
logger.error("Exception thrown by websocket query \"" + this.getURI().toString() + "\"!");
|
||||
logger.error(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String arg0) {
|
||||
alive = true;
|
||||
if(pingTimer == -1) {
|
||||
pingTimer = System.currentTimeMillis() - pingStart;
|
||||
if(pingTimer < 1) {
|
||||
pingTimer = 1;
|
||||
}
|
||||
}
|
||||
if(arg0.equalsIgnoreCase("BLOCKED")) {
|
||||
logger.error("Reached full IP ratelimit for {}!", this.uri.toString());
|
||||
rateLimit = EnumServerRateLimit.BLOCKED;
|
||||
return;
|
||||
}
|
||||
if(arg0.equalsIgnoreCase("LOCKED")) {
|
||||
logger.error("Reached full IP ratelimit lockout for {}!", this.uri.toString());
|
||||
rateLimit = EnumServerRateLimit.LOCKED_OUT;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JSONObject obj = new JSONObject(arg0);
|
||||
if("blocked".equalsIgnoreCase(obj.optString("type", null))) {
|
||||
logger.error("Reached query ratelimit for {}!", this.uri.toString());
|
||||
rateLimit = EnumServerRateLimit.BLOCKED;
|
||||
}else if("locked".equalsIgnoreCase(obj.optString("type", null))) {
|
||||
logger.error("Reached query ratelimit lockout for {}!", this.uri.toString());
|
||||
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 \"" + this.getURI().toString() + "\"!");
|
||||
logger.error(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer arg0) {
|
||||
alive = true;
|
||||
if(pingTimer == -1) {
|
||||
pingTimer = System.currentTimeMillis() - pingStart;
|
||||
if(pingTimer < 1) {
|
||||
pingTimer = 1;
|
||||
}
|
||||
}
|
||||
synchronized(queryResponsesBytes) {
|
||||
queryResponsesBytes.add(arg0.array());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake arg0) {
|
||||
pingStart = System.currentTimeMillis();
|
||||
send("Accept: " + type);
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.lwjgl.system.jemalloc.JEmalloc;
|
||||
|
||||
import net.lax1dude.unsafememcpy.UnsafeMemcpy;
|
||||
import net.lax1dude.unsafememcpy.UnsafeUtils;
|
||||
|
||||
@ -29,7 +27,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
|
||||
EaglerLWJGLByteBuffer(long address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
@ -68,18 +66,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
public byte[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@ -88,50 +81,40 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer slice() {
|
||||
return new EaglerLWJGLByteBuffer(address + position, limit - position, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer duplicate() {
|
||||
return new EaglerLWJGLByteBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer asReadOnlyBuffer() {
|
||||
return new EaglerLWJGLByteBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return UnsafeUtils.getMemByte(address + position++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemByte(address + position++, b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemByte(address + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(int index, byte b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemByte(address + index, b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer get(byte[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpy(dst, offset, address + position, length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -139,7 +122,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer get(byte[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
|
||||
UnsafeMemcpy.memcpy(dst, 0, address + position, dst.length);
|
||||
position += dst.length;
|
||||
return this;
|
||||
@ -150,13 +133,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
if(src instanceof EaglerLWJGLByteBuffer) {
|
||||
EaglerLWJGLByteBuffer c = (EaglerLWJGLByteBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
UnsafeMemcpy.memcpy(address + position, c.address + c.position, l);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
UnsafeUtils.setMemByte(address + position + l, src.get());
|
||||
}
|
||||
@ -167,7 +150,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpy(address + position, src, offset, length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -175,39 +158,15 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer put(byte[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
|
||||
UnsafeMemcpy.memcpy(address + position, src, 0, src.length);
|
||||
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 EaglerLWJGLByteBuffer(0l, 0, false);
|
||||
}
|
||||
|
||||
int newLen = limit - position;
|
||||
long newAlloc = JEmalloc.nje_malloc(newLen);
|
||||
if(newAlloc == 0l) {
|
||||
throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
|
||||
}
|
||||
UnsafeMemcpy.memcpy(newAlloc, address + position, newLen);
|
||||
|
||||
return new EaglerLWJGLByteBuffer(newAlloc, newLen, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar() {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
char c = UnsafeUtils.getMemChar(address + position);
|
||||
position += 2;
|
||||
return c;
|
||||
@ -215,7 +174,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer putChar(char value) {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemChar(address + position, value);
|
||||
position += 2;
|
||||
return this;
|
||||
@ -223,20 +182,20 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public char getChar(int index) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemChar(address + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putChar(int index, char value) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemChar(address + index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
short s = UnsafeUtils.getMemShort(address + position);
|
||||
position += 2;
|
||||
return s;
|
||||
@ -244,7 +203,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer putShort(short value) {
|
||||
if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 2 > limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemShort(address + position, value);
|
||||
position += 2;
|
||||
return this;
|
||||
@ -252,13 +211,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public short getShort(int index) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemShort(address + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putShort(int index, short value) {
|
||||
if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemShort(address + index, value);
|
||||
return this;
|
||||
}
|
||||
@ -270,7 +229,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
int i = UnsafeUtils.getMemInt(address + position);
|
||||
position += 4;
|
||||
return i;
|
||||
@ -278,7 +237,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer putInt(int value) {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemInt(address + position, value);
|
||||
position += 4;
|
||||
return this;
|
||||
@ -286,13 +245,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public int getInt(int index) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemInt(address + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putInt(int index, int value) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemInt(address + index, value);
|
||||
return this;
|
||||
}
|
||||
@ -304,7 +263,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 8 > limit) throw Buffer.makeIOOBE(position);
|
||||
long l = UnsafeUtils.getMemLong(address + position);
|
||||
position += 8;
|
||||
return l;
|
||||
@ -312,7 +271,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer putLong(long value) {
|
||||
if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 8 > limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemLong(address + position, value);
|
||||
position += 8;
|
||||
return this;
|
||||
@ -320,20 +279,20 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public long getLong(int index) {
|
||||
if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemLong(address + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putLong(int index, long value) {
|
||||
if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemLong(address + index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
float f = UnsafeUtils.getMemFloat(address + position);
|
||||
position += 4;
|
||||
return f;
|
||||
@ -341,7 +300,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer putFloat(float value) {
|
||||
if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position + 4 > limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemFloat(address + position, value);
|
||||
position += 4;
|
||||
return this;
|
||||
@ -349,13 +308,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public float getFloat(int index) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemFloat(address + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer putFloat(int index, float value) {
|
||||
if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemFloat(address + index, value);
|
||||
return this;
|
||||
}
|
||||
@ -374,7 +333,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
@Override
|
||||
public ByteBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
@ -404,14 +363,14 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
|
||||
|
||||
@Override
|
||||
public ByteBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.lwjgl.system.jemalloc.JEmalloc;
|
||||
|
||||
import net.lax1dude.unsafememcpy.UnsafeMemcpy;
|
||||
import net.lax1dude.unsafememcpy.UnsafeUtils;
|
||||
|
||||
@ -29,9 +27,9 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
|
||||
private static final int SHIFT = 2;
|
||||
|
||||
|
||||
EaglerLWJGLFloatBuffer(long address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
@ -70,82 +68,62 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
public float[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer slice() {
|
||||
return new EaglerLWJGLFloatBuffer(address + (position << SHIFT), limit - position, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer duplicate() {
|
||||
return new EaglerLWJGLFloatBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer asReadOnlyBuffer() {
|
||||
return new EaglerLWJGLFloatBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return UnsafeUtils.getMemFloat(address + ((position++) << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemFloat(address + ((position++) << SHIFT), b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemFloat(address + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(int index, float b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemFloat(address + (index << SHIFT), b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getElement(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemFloat(address + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, float value) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
UnsafeUtils.setMemFloat(address + ((position++) << SHIFT), value);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemFloat(address + (index << SHIFT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer get(float[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -153,7 +131,7 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
|
||||
@Override
|
||||
public FloatBuffer get(float[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, 0, address + (position << SHIFT), dst.length);
|
||||
position += dst.length;
|
||||
return this;
|
||||
@ -164,13 +142,13 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
if(src instanceof EaglerLWJGLFloatBuffer) {
|
||||
EaglerLWJGLFloatBuffer c = (EaglerLWJGLFloatBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
UnsafeMemcpy.memcpy(address + (position << SHIFT), c.address + (c.position << SHIFT), l << SHIFT);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
UnsafeUtils.setMemFloat(address + ((position + l) << SHIFT), src.get());
|
||||
}
|
||||
@ -181,7 +159,7 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -189,36 +167,12 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
|
||||
@Override
|
||||
public FloatBuffer put(float[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, 0, src.length);
|
||||
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 EaglerLWJGLFloatBuffer(0l, 0, false);
|
||||
}
|
||||
|
||||
int newLen = limit - position;
|
||||
long newAlloc = JEmalloc.nje_malloc(newLen);
|
||||
if(newAlloc == 0l) {
|
||||
throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
|
||||
}
|
||||
UnsafeMemcpy.memcpy(newAlloc, address + (position << SHIFT), newLen << SHIFT);
|
||||
|
||||
return new EaglerLWJGLFloatBuffer(newAlloc, newLen, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
@ -233,7 +187,7 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
@Override
|
||||
public FloatBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
@ -263,14 +217,14 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
|
||||
|
||||
@Override
|
||||
public FloatBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.lwjgl.system.jemalloc.JEmalloc;
|
||||
|
||||
import net.lax1dude.unsafememcpy.UnsafeMemcpy;
|
||||
import net.lax1dude.unsafememcpy.UnsafeUtils;
|
||||
|
||||
@ -21,7 +19,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils;
|
||||
*
|
||||
*/
|
||||
public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
|
||||
|
||||
final long address;
|
||||
final boolean original;
|
||||
|
||||
@ -29,9 +27,9 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
|
||||
private static final int SHIFT = 2;
|
||||
|
||||
|
||||
EaglerLWJGLIntBuffer(long address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
@ -44,7 +42,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
this.mark = mark;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
@ -70,82 +68,62 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
public int[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer slice() {
|
||||
return new EaglerLWJGLIntBuffer(address + (position << SHIFT), limit - position, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer duplicate() {
|
||||
return new EaglerLWJGLIntBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer asReadOnlyBuffer() {
|
||||
return new EaglerLWJGLIntBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return UnsafeUtils.getMemInt(address + ((position++) << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemInt(address + ((position++) << SHIFT), b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemInt(address + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int index, int b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemInt(address + (index << SHIFT), b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getElement(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemInt(address + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, int value) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemInt(address + (index << SHIFT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer get(int[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -153,7 +131,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
|
||||
@Override
|
||||
public IntBuffer get(int[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, 0, address + (position << SHIFT), dst.length);
|
||||
position += dst.length;
|
||||
return this;
|
||||
@ -164,13 +142,13 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
if(src instanceof EaglerLWJGLIntBuffer) {
|
||||
EaglerLWJGLIntBuffer c = (EaglerLWJGLIntBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
UnsafeMemcpy.memcpy(address + (position << SHIFT), c.address + (c.position << SHIFT), l << SHIFT);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
UnsafeUtils.setMemInt(address + ((position + l) << SHIFT), src.get());
|
||||
}
|
||||
@ -181,7 +159,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -189,36 +167,12 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
|
||||
@Override
|
||||
public IntBuffer put(int[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, 0, src.length);
|
||||
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 EaglerLWJGLIntBuffer(0l, 0, false);
|
||||
}
|
||||
|
||||
int newLen = limit - position;
|
||||
long newAlloc = JEmalloc.nje_malloc(newLen);
|
||||
if(newAlloc == 0l) {
|
||||
throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
|
||||
}
|
||||
UnsafeMemcpy.memcpy(newAlloc, address + (position << SHIFT), newLen << SHIFT);
|
||||
|
||||
return new EaglerLWJGLIntBuffer(newAlloc, newLen, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
@ -233,7 +187,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
@Override
|
||||
public IntBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
@ -263,14 +217,14 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
|
||||
|
||||
@Override
|
||||
public IntBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
|
||||
import org.lwjgl.system.jemalloc.JEmalloc;
|
||||
|
||||
import net.lax1dude.unsafememcpy.UnsafeMemcpy;
|
||||
import net.lax1dude.unsafememcpy.UnsafeUtils;
|
||||
|
||||
@ -21,7 +19,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils;
|
||||
*
|
||||
*/
|
||||
public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
|
||||
|
||||
final long address;
|
||||
final boolean original;
|
||||
|
||||
@ -29,9 +27,9 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
private int position;
|
||||
private int limit;
|
||||
private int mark;
|
||||
|
||||
|
||||
private static final int SHIFT = 1;
|
||||
|
||||
|
||||
EaglerLWJGLShortBuffer(long address, int capacity, boolean original) {
|
||||
this(address, capacity, 0, capacity, -1, original);
|
||||
}
|
||||
@ -44,7 +42,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
this.mark = mark;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return capacity;
|
||||
@ -70,82 +68,62 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
return position < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object array() {
|
||||
public short[] array() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer slice() {
|
||||
return new EaglerLWJGLShortBuffer(address + (position << SHIFT), limit - position, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer duplicate() {
|
||||
return new EaglerLWJGLShortBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer asReadOnlyBuffer() {
|
||||
return new EaglerLWJGLShortBuffer(address, capacity, position, limit, mark, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short get() {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
return UnsafeUtils.getMemShort(address + ((position++) << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short b) {
|
||||
if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
|
||||
if(position >= limit) throw Buffer.makeIOOBE(position);
|
||||
UnsafeUtils.setMemShort(address + ((position++) << SHIFT), b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short get(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemShort(address + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(int index, short b) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemShort(address + (index << SHIFT), b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getElement(int index) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
return UnsafeUtils.getMemShort(address + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(int index, short value) {
|
||||
if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
|
||||
if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
|
||||
UnsafeUtils.setMemShort(address + (index << SHIFT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer get(short[] dst, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -153,7 +131,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
|
||||
@Override
|
||||
public ShortBuffer get(short[] dst) {
|
||||
if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
|
||||
if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
|
||||
UnsafeMemcpy.memcpyAlignDst(dst, 0, address + (position << SHIFT), dst.length);
|
||||
position += dst.length;
|
||||
return this;
|
||||
@ -164,13 +142,13 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
if(src instanceof EaglerLWJGLShortBuffer) {
|
||||
EaglerLWJGLShortBuffer c = (EaglerLWJGLShortBuffer)src;
|
||||
int l = c.limit - c.position;
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
UnsafeMemcpy.memcpy(address + (position << SHIFT), c.address + (c.position << SHIFT), l << SHIFT);
|
||||
position += l;
|
||||
c.position += l;
|
||||
}else {
|
||||
int l = src.remaining();
|
||||
if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
|
||||
if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
UnsafeUtils.setMemInt(address + ((position + l) << SHIFT), src.get());
|
||||
}
|
||||
@ -181,7 +159,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short[] src, int offset, int length) {
|
||||
if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
|
||||
if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
|
||||
position += length;
|
||||
return this;
|
||||
@ -189,36 +167,12 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
|
||||
@Override
|
||||
public ShortBuffer put(short[] src) {
|
||||
if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
|
||||
if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
|
||||
UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, 0, src.length);
|
||||
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 EaglerLWJGLShortBuffer(0l, 0, false);
|
||||
}
|
||||
|
||||
int newLen = limit - position;
|
||||
long newAlloc = JEmalloc.nje_malloc(newLen);
|
||||
if(newAlloc == 0l) {
|
||||
throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
|
||||
}
|
||||
UnsafeMemcpy.memcpy(newAlloc, address + (position << SHIFT), newLen << SHIFT);
|
||||
|
||||
return new EaglerLWJGLShortBuffer(newAlloc, newLen, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return true;
|
||||
@ -233,7 +187,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
@Override
|
||||
public ShortBuffer reset() {
|
||||
int m = mark;
|
||||
if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
|
||||
if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
|
||||
position = m;
|
||||
return this;
|
||||
}
|
||||
@ -263,14 +217,14 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
|
||||
|
||||
@Override
|
||||
public ShortBuffer limit(int newLimit) {
|
||||
if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
|
||||
if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBuffer position(int newPosition) {
|
||||
if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
|
||||
if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
@ -27,21 +28,33 @@ import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFSIterator2.BreakLoop;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DebugFilesystem implements PlatformFilesystem.IFilesystemProvider {
|
||||
public class DebugFilesystem implements IEaglerFilesystem {
|
||||
|
||||
public static DebugFilesystem initialize(File filesystemRoot) {
|
||||
public static DebugFilesystem initialize(String fsName, File filesystemRoot) {
|
||||
if(!filesystemRoot.isDirectory() && !filesystemRoot.mkdirs()) {
|
||||
throw new EaglerFileSystemException("Could not create directory for virtual filesystem: " + filesystemRoot.getAbsolutePath());
|
||||
}
|
||||
return new DebugFilesystem(filesystemRoot);
|
||||
return new DebugFilesystem(fsName, filesystemRoot);
|
||||
}
|
||||
|
||||
private final File filesystemRoot;
|
||||
private final String fsName;
|
||||
|
||||
private DebugFilesystem(File root) {
|
||||
private DebugFilesystem(String fsName, File root) {
|
||||
this.fsName = fsName;
|
||||
this.filesystemRoot = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilesystemName() {
|
||||
return fsName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalDBName() {
|
||||
return "desktopruntime:" + filesystemRoot.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerDelete(String pathName) {
|
||||
File f = getJREFile(pathName);
|
||||
@ -78,7 +91,7 @@ public class DebugFilesystem implements PlatformFilesystem.IFilesystemProvider {
|
||||
return tmp;
|
||||
}catch (IOException e) {
|
||||
throw new EaglerFileSystemException("Failed to read: " + f.getAbsolutePath(), e);
|
||||
}catch(ArrayIndexOutOfBoundsException ex) {
|
||||
}catch(IndexOutOfBoundsException ex) {
|
||||
throw new EaglerFileSystemException("ERROR: Expected " + fileSize + " bytes, buffer overflow reading: " + f.getAbsolutePath(), ex);
|
||||
}finally {
|
||||
if(buf != null) {
|
||||
@ -221,4 +234,15 @@ public class DebugFilesystem implements PlatformFilesystem.IFilesystemProvider {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRamdisk() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHandle() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
|
||||
|
||||
public static final IClientConfigAdapter instance = new DesktopClientConfigAdapter();
|
||||
|
||||
public final List<DefaultServer> defaultServers = new ArrayList();
|
||||
public final List<DefaultServer> defaultServers = new ArrayList<>();
|
||||
|
||||
private final DesktopClientConfigAdapterHooks hooks = new DesktopClientConfigAdapterHooks();
|
||||
|
||||
@ -52,17 +52,17 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
|
||||
|
||||
@Override
|
||||
public String getWorldsDB() {
|
||||
return "desktop";
|
||||
return "worlds";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourcePacksDB() {
|
||||
return "desktop";
|
||||
return "resourcePacks";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getIntegratedServerOpts() {
|
||||
return new JSONObject("{\"container\":null,\"worldsDB\":\"desktop\"}");
|
||||
return new JSONObject("{\"container\":null,\"worldsDB\":\"worlds\"}");
|
||||
}
|
||||
|
||||
private final List<RelayEntry> relays = new ArrayList<>();
|
||||
@ -148,6 +148,51 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableServerCookies() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowServerRedirects() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpenDebugConsoleOnLaunch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceWebViewSupport() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableWebViewCSP() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowBootMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceProfanityFilter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEaglerNoDelay() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRamdiskMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
@ -170,5 +215,12 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callScreenChangedHook(String screenName, int scaledWidth, int scaledHeight, int realWidth,
|
||||
int realHeight, int scaleFactor) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,109 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.AbstractWebSocketClient;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DesktopWebSocketClient extends AbstractWebSocketClient {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("DesktopWebSocketClient");
|
||||
|
||||
volatile EnumEaglerConnectionState playConnectState = EnumEaglerConnectionState.CONNECTING;
|
||||
final Object connectOpenMutex = new Object();
|
||||
final WebSocketClientImpl clientImpl;
|
||||
final URI currentURI;
|
||||
final String currentURIStr;
|
||||
|
||||
public DesktopWebSocketClient(URI currentURI) {
|
||||
super(currentURI.toString());
|
||||
this.currentURI = currentURI;
|
||||
currentURIStr = currentURI.toString();
|
||||
clientImpl = new WebSocketClientImpl(this, currentURI);
|
||||
clientImpl.addHeader("Origin", "EAG_LWJGL_" + (EaglercraftVersion.projectForkName + "_"
|
||||
+ EaglercraftVersion.projectOriginVersion).replaceAll("[^a-zA-Z0-9\\-_\\.]", "_"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumEaglerConnectionState getState() {
|
||||
return playConnectState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connectBlocking(int timeoutMS) {
|
||||
synchronized(connectOpenMutex) {
|
||||
try {
|
||||
connectOpenMutex.wait(timeoutMS);
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return playConnectState.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return playConnectState.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return playConnectState.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(!playConnectState.isClosed()) {
|
||||
try {
|
||||
clientImpl.closeBlocking();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
playConnectState = EnumEaglerConnectionState.CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String str) {
|
||||
if(clientImpl.isClosed()) {
|
||||
logger.error("[{}]: Client tried to send {} char packet while the socket was closed!", currentURIStr, str.length());
|
||||
}else {
|
||||
clientImpl.send(str);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(byte[] bytes) {
|
||||
if(clientImpl.isClosed()) {
|
||||
logger.error("[{}]: Client tried to send {} byte packet while the socket was closed!", currentURIStr, bytes.length);
|
||||
}else {
|
||||
clientImpl.send(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleString(String str) {
|
||||
addRecievedFrame(new DesktopWebSocketFrameString(str));
|
||||
}
|
||||
|
||||
public void handleBytes(byte[] array) {
|
||||
addRecievedFrame(new DesktopWebSocketFrameBinary(array));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DesktopWebSocketFrameBinary implements IWebSocketFrame {
|
||||
|
||||
private final byte[] byteArray;
|
||||
private final long timestamp;
|
||||
|
||||
public DesktopWebSocketFrameBinary(byte[] byteArray) {
|
||||
this.byteArray = byteArray;
|
||||
this.timestamp = PlatformRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isString() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return new EaglerInputStream(byteArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return byteArray.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class DesktopWebSocketFrameString implements IWebSocketFrame {
|
||||
|
||||
private final String string;
|
||||
private final long timestamp;
|
||||
|
||||
public DesktopWebSocketFrameString(String string) {
|
||||
this.string = string;
|
||||
this.timestamp = PlatformRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isString() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return string.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
import fi.iki.elonen.NanoHTTPD.Response.Status;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
class FallbackWebViewHTTPD extends NanoHTTPD {
|
||||
|
||||
static final Logger logger = FallbackWebViewServer.logger;
|
||||
|
||||
private String index;
|
||||
|
||||
FallbackWebViewHTTPD(String hostname, int port, String index) {
|
||||
super(hostname, port);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response serve(IHTTPSession session) {
|
||||
if("/RTWebViewClient".equals(session.getUri())) {
|
||||
return newFixedLengthResponse(Status.OK, MIME_HTML, index);
|
||||
}else {
|
||||
return newFixedLengthResponse(Status.NOT_FOUND, MIME_HTML, "<!DOCTYPE html><html><head><title>Eaglercraft Desktop Runtime</title></head><body><h1>404 Not Found</h1></body></html>");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,299 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
class FallbackWebViewProtocol {
|
||||
|
||||
static final Logger logger = FallbackWebViewServer.logger;
|
||||
|
||||
private static final Map<Integer,Class<? extends FallbackWebViewPacket>> packetIDToClass = new HashMap<>();
|
||||
private static final Map<Class<? extends FallbackWebViewPacket>,Integer> packetClassToID = new HashMap<>();
|
||||
|
||||
private static final int CLIENT_TO_SERVER = 0;
|
||||
private static final int SERVER_TO_CLIENT = 1;
|
||||
|
||||
static {
|
||||
register(0x00, CLIENT_TO_SERVER, CPacketClientHandshake.class);
|
||||
register(0x01, SERVER_TO_CLIENT, SPacketServerHandshake.class);
|
||||
register(0x02, SERVER_TO_CLIENT, SPacketServerError.class);
|
||||
register(0x03, CLIENT_TO_SERVER, CPacketWebViewChannelOpen.class);
|
||||
register(0x04, CLIENT_TO_SERVER, CPacketWebViewChannelClose.class);
|
||||
register(0x05, CLIENT_TO_SERVER, CPacketWebViewMessage.class);
|
||||
register(0x06, SERVER_TO_CLIENT, SPacketWebViewMessage.class);
|
||||
register(0x07, CLIENT_TO_SERVER, CPacketWebViewJSPermission.class);
|
||||
}
|
||||
|
||||
private static void register(int id, int dir, Class<? extends FallbackWebViewPacket> packet) {
|
||||
if(dir == CLIENT_TO_SERVER) {
|
||||
packetIDToClass.put(id, packet);
|
||||
}else if(dir == SERVER_TO_CLIENT) {
|
||||
packetClassToID.put(packet, id);
|
||||
}else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
static String writePacket(FallbackWebViewPacket packet) {
|
||||
Class<? extends FallbackWebViewPacket> cls = packet.getClass();
|
||||
Integer id = packetClassToID.get(cls);
|
||||
if(id == null) {
|
||||
throw new RuntimeException("Tried to send unknown packet to client: " + cls.getSimpleName());
|
||||
}
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("$", id);
|
||||
packet.writePacket(json);
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
static FallbackWebViewPacket readPacket(String data) {
|
||||
try {
|
||||
JSONObject json = new JSONObject(data);
|
||||
int id = json.getInt("$");
|
||||
Class<? extends FallbackWebViewPacket> cls = packetIDToClass.get(id);
|
||||
if(cls == null) {
|
||||
logger.error("Unknown packet ID {} recieved from webview controller", id);
|
||||
return null;
|
||||
}
|
||||
FallbackWebViewPacket ret;
|
||||
try {
|
||||
ret = cls.newInstance();
|
||||
}catch(Throwable t) {
|
||||
throw new RuntimeException("Failed to call packet constructor for \"" + cls.getSimpleName() + "\"! (is it defined?)");
|
||||
}
|
||||
ret.readPacket(json);
|
||||
return ret;
|
||||
}catch(Throwable ex) {
|
||||
logger.error("Failed to parse message from webview controller: \"{}\"", data);
|
||||
logger.error(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static interface FallbackWebViewPacket {
|
||||
|
||||
void readPacket(JSONObject json);
|
||||
|
||||
void writePacket(JSONObject json);
|
||||
|
||||
}
|
||||
|
||||
static class CPacketClientHandshake implements FallbackWebViewPacket {
|
||||
|
||||
public boolean cspSupport;
|
||||
|
||||
public CPacketClientHandshake() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
cspSupport = json.getBoolean("cspSupport");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Client only!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CPacketWebViewChannelOpen implements FallbackWebViewPacket {
|
||||
|
||||
public String messageChannel;
|
||||
|
||||
public CPacketWebViewChannelOpen() {
|
||||
}
|
||||
|
||||
public CPacketWebViewChannelOpen(String messageChannel) {
|
||||
this.messageChannel = messageChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
messageChannel = json.getString("channel");
|
||||
if(messageChannel.length() > 255) {
|
||||
throw new JSONException("Channel name too long!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Client only!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CPacketWebViewChannelClose implements FallbackWebViewPacket {
|
||||
|
||||
public CPacketWebViewChannelClose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Client only!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// for string messages, binary are sent as a binary frame
|
||||
static class CPacketWebViewMessage implements FallbackWebViewPacket {
|
||||
|
||||
public String messageContent;
|
||||
|
||||
public CPacketWebViewMessage() {
|
||||
}
|
||||
|
||||
public CPacketWebViewMessage(String messageContent) {
|
||||
this.messageContent = messageContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
messageContent = json.getString("msg");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Client only!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SPacketServerHandshake implements FallbackWebViewPacket {
|
||||
|
||||
public WebViewOptions options;
|
||||
public EnumWebViewJSPermission hasApprovedJS;
|
||||
|
||||
public SPacketServerHandshake() {
|
||||
}
|
||||
|
||||
public SPacketServerHandshake(WebViewOptions options, EnumWebViewJSPermission hasApprovedJS) {
|
||||
this.options = options;
|
||||
this.hasApprovedJS = hasApprovedJS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Server only!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
json.put("contentMode", options.contentMode.toString());
|
||||
json.put("fallbackTitle", options.fallbackTitle);
|
||||
json.put("scriptEnabled", options.scriptEnabled);
|
||||
json.put("strictCSPEnable", options.strictCSPEnable);
|
||||
json.put("serverMessageAPIEnabled", options.serverMessageAPIEnabled);
|
||||
json.put("url", options.url);
|
||||
json.put("blob", options.blob != null ? new String(options.blob, StandardCharsets.UTF_8) : null);
|
||||
json.put("hasApprovedJS", hasApprovedJS.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SPacketServerError implements FallbackWebViewPacket {
|
||||
|
||||
public String errorMessage;
|
||||
|
||||
public SPacketServerError() {
|
||||
}
|
||||
|
||||
public SPacketServerError(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Server only!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
json.put("msg", errorMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SPacketWebViewMessage implements FallbackWebViewPacket {
|
||||
|
||||
public String message;
|
||||
|
||||
public SPacketWebViewMessage() {
|
||||
}
|
||||
|
||||
public SPacketWebViewMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Server only!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
json.put("msg", message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static enum EnumWebViewJSPermission {
|
||||
NOT_SET, ALLOW, BLOCK;
|
||||
|
||||
static EnumWebViewJSPermission fromPermission(PermissionsCache.Permission perm) {
|
||||
if(perm != null) {
|
||||
return perm.choice ? ALLOW : BLOCK;
|
||||
}else {
|
||||
return NOT_SET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class CPacketWebViewJSPermission implements FallbackWebViewPacket {
|
||||
|
||||
public EnumWebViewJSPermission permission;
|
||||
|
||||
public CPacketWebViewJSPermission() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacket(JSONObject json) {
|
||||
permission = EnumWebViewJSPermission.valueOf(json.getString("perm"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacket(JSONObject json) {
|
||||
throw new UnsupportedOperationException("Client only!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class FallbackWebViewServer {
|
||||
|
||||
static final Logger logger = LogManager.getLogger("FallbackWebViewServer");
|
||||
|
||||
public static final String LISTEN_ADDR = "127.69.69.69";
|
||||
|
||||
public static final File webViewClientHTML = new File("RTWebViewClient.html");
|
||||
|
||||
public final WebViewOptions options;
|
||||
|
||||
private FallbackWebViewWSD websocketServer;
|
||||
private FallbackWebViewHTTPD httpServer;
|
||||
|
||||
private String currentURL;
|
||||
private volatile boolean dead;
|
||||
|
||||
private IPacketSendCallback callback = null;
|
||||
|
||||
public FallbackWebViewServer(WebViewOptions options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public void start() throws RuntimeException {
|
||||
dead = false;
|
||||
StringBuilder vigg = new StringBuilder();
|
||||
try(BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(new FileInputStream(webViewClientHTML), StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while((line = reader.readLine()) != null) {
|
||||
vigg.append(line).append('\n');
|
||||
}
|
||||
}catch(IOException ex) {
|
||||
logger.error("Failed to read \"{}\"!");
|
||||
}
|
||||
String indexHTML = vigg.toString();
|
||||
|
||||
Object mutex = new Object();
|
||||
websocketServer = new FallbackWebViewWSD(LISTEN_ADDR, randomPort(), options);
|
||||
websocketServer.setEaglerPacketSendCallback(callback);
|
||||
synchronized(mutex) {
|
||||
websocketServer.doStartup(mutex);
|
||||
try {
|
||||
mutex.wait(5000l);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
if(!websocketServer.hasStarted) {
|
||||
logger.error("Failed to start WebSocket in time!");
|
||||
try {
|
||||
websocketServer.stop(5000);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
websocketServer = null;
|
||||
throw new RuntimeException("Failed to start WebSocket server!");
|
||||
}
|
||||
InetSocketAddress addr = websocketServer.getAddress();
|
||||
String wsAddr = "ws://" + addr.getHostString() + ":" + addr.getPort() + "/";
|
||||
logger.info("Listening for WebSocket on {}", wsAddr);
|
||||
indexHTML = indexHTML.replace("${client_websocket_uri}", wsAddr);
|
||||
|
||||
JSONObject optsExport = new JSONObject();
|
||||
IClientConfigAdapter cfgAdapter = PlatformRuntime.getClientConfigAdapter();
|
||||
optsExport.put("forceWebViewSupport", cfgAdapter.isForceWebViewSupport());
|
||||
optsExport.put("enableWebViewCSP", cfgAdapter.isEnableWebViewCSP());
|
||||
indexHTML = indexHTML.replace("{eaglercraftXOpts}", optsExport.toString());
|
||||
|
||||
httpServer = new FallbackWebViewHTTPD(LISTEN_ADDR, 0, indexHTML);
|
||||
try {
|
||||
httpServer.start(5000, true);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to start NanoHTTPD!");
|
||||
try {
|
||||
websocketServer.stop(5000);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
websocketServer = null;
|
||||
httpServer = null;
|
||||
throw new RuntimeException("Failed to start NanoHTTPD!", e);
|
||||
}
|
||||
int httpPort = httpServer.getListeningPort();
|
||||
currentURL = "http://" + LISTEN_ADDR + ":" + httpPort + "/RTWebViewClient";
|
||||
logger.info("Listening for HTTP on {}", currentURL);
|
||||
}
|
||||
|
||||
private int randomPort() {
|
||||
try(ServerSocket sockler = new ServerSocket(0)) {
|
||||
return sockler.getLocalPort();
|
||||
}catch(IOException ex) {
|
||||
throw new RuntimeException("Failed to find random port to bind to!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDead() {
|
||||
return dead;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return !dead ? currentURL : null;
|
||||
}
|
||||
|
||||
public void handleMessageFromServer(SPacketWebViewMessageV4EAG packet) {
|
||||
if(packet.type == SPacketWebViewMessageV4EAG.TYPE_STRING) {
|
||||
if(websocketServer != null) {
|
||||
websocketServer.handleServerMessageStr(new String(packet.data, StandardCharsets.UTF_8));
|
||||
}else {
|
||||
logger.error("Recieved string message, but the webview server is not running!");
|
||||
}
|
||||
}else if(packet.type == SPacketWebViewMessageV4EAG.TYPE_BINARY) {
|
||||
if(websocketServer != null) {
|
||||
websocketServer.handleServerMessageBytes(packet.data);
|
||||
}else {
|
||||
logger.error("Recieved string message, but the webview server is not running!");
|
||||
}
|
||||
}else {
|
||||
logger.error("Unknown server webview message type {}", packet.type);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPacketSendCallback(IPacketSendCallback callback) {
|
||||
this.callback = callback;
|
||||
if(websocketServer != null) {
|
||||
websocketServer.setEaglerPacketSendCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public void runTick() {
|
||||
|
||||
}
|
||||
|
||||
public void killServer() {
|
||||
if(!dead) {
|
||||
dead = true;
|
||||
if(websocketServer != null) {
|
||||
try {
|
||||
websocketServer.stop(10000);
|
||||
} catch (Throwable th) {
|
||||
logger.error("Failed to stop WebSocket server, aborting");
|
||||
logger.error(th);
|
||||
}
|
||||
websocketServer = null;
|
||||
}
|
||||
if(httpServer != null) {
|
||||
try {
|
||||
httpServer.stop();
|
||||
} catch (Throwable th) {
|
||||
logger.error("Failed to stop HTTP server, aborting");
|
||||
logger.error(th);
|
||||
}
|
||||
httpServer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,273 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageEnV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache.Permission;
|
||||
import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
|
||||
|
||||
import static net.lax1dude.eaglercraft.v1_8.internal.lwjgl.FallbackWebViewProtocol.*;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
class FallbackWebViewWSD extends WebSocketServer {
|
||||
|
||||
static final Logger logger = FallbackWebViewServer.logger;
|
||||
|
||||
private Object onStartNotify;
|
||||
|
||||
volatile boolean hasStarted = false;
|
||||
|
||||
private final Object webSockMutex = new Object();
|
||||
volatile WebSocket webSocket = null;
|
||||
|
||||
volatile boolean hasHandshake = false;
|
||||
volatile String currentChannelName = null;
|
||||
|
||||
private IPacketSendCallback callback = null;
|
||||
WebViewOptions options;
|
||||
|
||||
private boolean enableCSP;
|
||||
private boolean cspSupport;
|
||||
|
||||
FallbackWebViewWSD(String address, int port, WebViewOptions options) {
|
||||
super(new InetSocketAddress(address, port), 1);
|
||||
this.setTcpNoDelay(true);
|
||||
this.setReuseAddr(true);
|
||||
this.setConnectionLostTimeout(30);
|
||||
this.options = options;
|
||||
this.enableCSP = PlatformRuntime.getClientConfigAdapter().isEnableWebViewCSP();
|
||||
this.cspSupport = true;
|
||||
}
|
||||
|
||||
public void doStartup(Object onStartNotify) {
|
||||
this.onStartNotify = onStartNotify;
|
||||
this.start();
|
||||
}
|
||||
|
||||
private void handleOpen() {
|
||||
hasHandshake = false;
|
||||
currentChannelName = null;
|
||||
}
|
||||
|
||||
private void handleClose() {
|
||||
if(currentChannelName != null && callback != null) {
|
||||
callback.sendPacket(new CPacketWebViewMessageEnV4EAG(false, null));
|
||||
}
|
||||
currentChannelName = null;
|
||||
}
|
||||
|
||||
private int hashPermissionFlags() {
|
||||
int i = (options.scriptEnabled ? 1 : 0);
|
||||
i |= ((enableCSP && cspSupport && options.strictCSPEnable) ? 0 : 2);
|
||||
i |= (options.serverMessageAPIEnabled ? 4 : 0);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void handleMessage(String str) {
|
||||
WebSocket ws = webSocket;
|
||||
FallbackWebViewPacket _packet = readPacket(str);
|
||||
if(_packet != null) {
|
||||
if(!hasHandshake) {
|
||||
if(_packet instanceof CPacketClientHandshake) {
|
||||
hasHandshake = true;
|
||||
Permission perm = PermissionsCache.getJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags());
|
||||
ws.send(writePacket(new SPacketServerHandshake(options, EnumWebViewJSPermission.fromPermission(perm))));
|
||||
}else {
|
||||
terminate("Unknown or unexpected packet: " + _packet.getClass().getSimpleName());
|
||||
}
|
||||
}else {
|
||||
if(_packet instanceof CPacketWebViewChannelOpen) {
|
||||
CPacketWebViewChannelOpen packet = (CPacketWebViewChannelOpen)_packet;
|
||||
if(currentChannelName == null) {
|
||||
currentChannelName = packet.messageChannel;
|
||||
logger.info("[{}]: opened WebView channel \"{}\"", ws.getRemoteSocketAddress(), packet.messageChannel);
|
||||
safeCallbackSend(new CPacketWebViewMessageEnV4EAG(true, packet.messageChannel));
|
||||
}else {
|
||||
terminate("Tried to open multiple channels");
|
||||
}
|
||||
}else if(_packet instanceof CPacketWebViewMessage) {
|
||||
CPacketWebViewMessage packet = (CPacketWebViewMessage)_packet;
|
||||
if(currentChannelName != null) {
|
||||
safeCallbackSend(new CPacketWebViewMessageV4EAG(packet.messageContent));
|
||||
}else {
|
||||
terminate("Tried to send message without opening channel");
|
||||
}
|
||||
}else if(_packet instanceof CPacketWebViewChannelClose) {
|
||||
if(currentChannelName != null) {
|
||||
currentChannelName = null;
|
||||
safeCallbackSend(new CPacketWebViewMessageEnV4EAG(false, null));
|
||||
}else {
|
||||
terminate("Tried to close missing channel");
|
||||
}
|
||||
}else if(_packet instanceof CPacketWebViewJSPermission) {
|
||||
CPacketWebViewJSPermission packet = (CPacketWebViewJSPermission)_packet;
|
||||
switch(packet.permission) {
|
||||
case NOT_SET:
|
||||
PermissionsCache.clearJavaScriptAllowed(options.permissionsOriginUUID);
|
||||
break;
|
||||
case ALLOW:
|
||||
PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(), true);
|
||||
break;
|
||||
case BLOCK:
|
||||
PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(), false);
|
||||
break;
|
||||
default:
|
||||
terminate("Unknown permission state selected!");
|
||||
break;
|
||||
}
|
||||
|
||||
}else {
|
||||
terminate("Unknown or unexpected packet: " + _packet.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
}else {
|
||||
terminate("Invalid packet recieved");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMessage(ByteBuffer buffer) {
|
||||
if(currentChannelName != null) {
|
||||
safeCallbackSend(new CPacketWebViewMessageV4EAG(buffer.array()));
|
||||
}else {
|
||||
terminate("Sent binary webview message while channel was closed");
|
||||
}
|
||||
}
|
||||
|
||||
private void terminate(String msg) {
|
||||
if(webSocket != null) {
|
||||
logger.error("[{}]: Terminating connection, reason: \"{}\"", webSocket.getRemoteSocketAddress(), msg);
|
||||
webSocket.send(writePacket(new SPacketServerError(msg)));
|
||||
webSocket.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void safeCallbackSend(GameMessagePacket packet) {
|
||||
if(callback != null) {
|
||||
callback.sendPacket(packet);
|
||||
}else {
|
||||
logger.error("webview sent packet to server, but there's no callback registered to send packets!");
|
||||
}
|
||||
}
|
||||
|
||||
void handleServerMessageStr(String msg) {
|
||||
if(webSocket != null) {
|
||||
if(currentChannelName != null) {
|
||||
webSocket.send(writePacket(new SPacketWebViewMessage(msg)));
|
||||
}else {
|
||||
logger.error("Recieved string message from server, but the channel is not open!");
|
||||
}
|
||||
}else {
|
||||
logger.error("Recieved string message from server, but there is no active websocket!");
|
||||
}
|
||||
}
|
||||
|
||||
void handleServerMessageBytes(byte[] msg) {
|
||||
if(webSocket != null) {
|
||||
if(currentChannelName != null) {
|
||||
webSocket.send(msg);
|
||||
}else {
|
||||
logger.error("Recieved binary message from server, but the channel is not open!");
|
||||
}
|
||||
}else {
|
||||
logger.error("Recieved binary message from server, but there is no active websocket!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
hasStarted = true;
|
||||
if(onStartNotify != null) {
|
||||
synchronized(onStartNotify) {
|
||||
onStartNotify.notifyAll();
|
||||
}
|
||||
onStartNotify = null;
|
||||
}else {
|
||||
logger.warn("No mutex to notify!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket arg0, ClientHandshake arg1) {
|
||||
boolean result;
|
||||
synchronized(webSockMutex) {
|
||||
if(webSocket == null) {
|
||||
webSocket = arg0;
|
||||
result = true;
|
||||
}else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
if(result) {
|
||||
logger.info("[{}]: WebSocket connection opened", arg0.getRemoteSocketAddress());
|
||||
handleOpen();
|
||||
}else {
|
||||
logger.error("[{}]: Rejecting duplicate connection", arg0.getRemoteSocketAddress());
|
||||
arg0.send(writePacket(new SPacketServerError("You already have a tab open!")));
|
||||
arg0.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket arg0, String arg1) {
|
||||
if(arg0 == webSocket) {
|
||||
handleMessage(arg1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket arg0, ByteBuffer arg1) {
|
||||
if(arg0 == webSocket) {
|
||||
handleMessage(arg1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) {
|
||||
synchronized(webSockMutex) {
|
||||
if(arg0 == webSocket) {
|
||||
logger.info("[{}]: WebSocket connection closed", arg0.getRemoteSocketAddress());
|
||||
try {
|
||||
handleClose();
|
||||
}finally {
|
||||
webSocket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket arg0, Exception arg1) {
|
||||
logger.error("[{}]: WebSocket caught exception", arg0 != null ? arg0.getRemoteSocketAddress() : "null");
|
||||
logger.error(arg1);
|
||||
}
|
||||
|
||||
public void setEaglerPacketSendCallback(IPacketSendCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
}
|
@ -13,8 +13,8 @@ import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.IFilesystemProvider;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
@ -38,15 +38,16 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class JDBCFilesystem implements IFilesystemProvider {
|
||||
public class JDBCFilesystem implements IEaglerFilesystem {
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("JDBCFilesystem");
|
||||
|
||||
private boolean newFilesystem = true;
|
||||
|
||||
private static volatile boolean cleanupThreadStarted = false;
|
||||
private static final Collection<JDBCFilesystem> jdbcFilesystems = new LinkedList();
|
||||
private static final Collection<JDBCFilesystem> jdbcFilesystems = new LinkedList<>();
|
||||
|
||||
private final String dbName;
|
||||
private final String jdbcUri;
|
||||
private final String jdbcDriver;
|
||||
|
||||
@ -64,8 +65,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
|
||||
|
||||
private final Object mutex = new Object();
|
||||
|
||||
public static IFilesystemProvider initialize(String jdbcUri, String jdbcDriver) {
|
||||
Class driver;
|
||||
public static IEaglerFilesystem initialize(String dbName, String jdbcUri, String jdbcDriver) {
|
||||
Class<?> driver;
|
||||
try {
|
||||
driver = Class.forName(jdbcDriver);
|
||||
} catch (ClassNotFoundException e) {
|
||||
@ -87,8 +88,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
|
||||
for(Entry<Object, Object> etr : System.getProperties().entrySet()) {
|
||||
if(etr.getKey() instanceof String) {
|
||||
String str = (String)etr.getKey();
|
||||
if(str.startsWith("eagler.jdbc.opts.")) {
|
||||
props.put(str.substring(17), etr.getValue());
|
||||
if(str.startsWith("eagler.jdbc." + dbName + ".opts.")) {
|
||||
props.put(str.substring(18 + dbName.length()), etr.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,7 +105,7 @@ public class JDBCFilesystem implements IFilesystemProvider {
|
||||
throw new EaglerFileSystemException("Failed to connect to database: \"" + jdbcUri + "\"", ex);
|
||||
}
|
||||
try {
|
||||
return new JDBCFilesystem(conn, jdbcUri, jdbcDriver);
|
||||
return new JDBCFilesystem(dbName, conn, jdbcUri, jdbcDriver);
|
||||
} catch (SQLException ex) {
|
||||
try {
|
||||
conn.close();
|
||||
@ -114,7 +115,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private JDBCFilesystem(Connection conn, String jdbcUri, String jdbcDriver) throws SQLException {
|
||||
private JDBCFilesystem(String dbName, Connection conn, String jdbcUri, String jdbcDriver) throws SQLException {
|
||||
this.dbName = dbName;
|
||||
this.conn = conn;
|
||||
this.jdbcUri = jdbcUri;
|
||||
this.jdbcDriver = jdbcDriver;
|
||||
@ -152,6 +154,16 @@ public class JDBCFilesystem implements IFilesystemProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilesystemName() {
|
||||
return dbName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalDBName() {
|
||||
return "desktopruntime:" + jdbcUri;
|
||||
}
|
||||
|
||||
public boolean isNewFilesystem() {
|
||||
return newFilesystem;
|
||||
}
|
||||
@ -172,7 +184,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
@Override
|
||||
public void closeHandle() {
|
||||
shutdown0();
|
||||
synchronized(jdbcFilesystems) {
|
||||
jdbcFilesystems.remove(this);
|
||||
@ -438,4 +451,9 @@ public class JDBCFilesystem implements IFilesystemProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRamdisk() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.IFilesystemProvider;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.EaglerFileSystemException;
|
||||
@ -33,7 +33,7 @@ public class JDBCFilesystemConverter {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("JDBCFilesystemConverter");
|
||||
|
||||
public static void convertFilesystem(String title, File oldFS, IFilesystemProvider newFS, boolean deleteOld) {
|
||||
public static void convertFilesystem(String title, File oldFS, IEaglerFilesystem newFS, boolean deleteOld) {
|
||||
FilesystemConvertingDialog progressDialog = new FilesystemConvertingDialog(title);
|
||||
try {
|
||||
progressDialog.setProgressIndeterminate(true);
|
||||
@ -41,7 +41,7 @@ public class JDBCFilesystemConverter {
|
||||
progressDialog.setVisible(true);
|
||||
|
||||
String slug = oldFS.getAbsolutePath();
|
||||
List<String> filesToCopy = new ArrayList();
|
||||
List<String> filesToCopy = new ArrayList<>();
|
||||
logger.info("Discovering files to convert...");
|
||||
iterateFolder(slug.length(), oldFS, filesToCopy);
|
||||
logger.info("Found {} files in the old directory", filesToCopy.size());
|
||||
|
@ -6,7 +6,6 @@ import javax.swing.UnsupportedLookAndFeelException;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformANGLE;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.ShaderSource;
|
||||
@ -82,11 +81,12 @@ public class LWJGLEntryPoint {
|
||||
PlatformInput.setStartupFullscreen(true);
|
||||
}else if(args[i].equalsIgnoreCase("highp")) {
|
||||
ShaderSource.setHighP(true);
|
||||
}else if(args[i].startsWith("jdbc:")) {
|
||||
if(i < args.length - 1) {
|
||||
PlatformFilesystem.setUseJDBC(args[i]);
|
||||
PlatformFilesystem.setJDBCDriverClass(args[++i]);
|
||||
}
|
||||
}else if(args[i].equalsIgnoreCase("gles=200")) {
|
||||
PlatformRuntime.requestGL(200);
|
||||
}else if(args[i].equalsIgnoreCase("gles=300")) {
|
||||
PlatformRuntime.requestGL(300);
|
||||
}else if(args[i].equalsIgnoreCase("gles=310")) {
|
||||
PlatformRuntime.requestGL(310);
|
||||
}else {
|
||||
EnumPlatformANGLE angle = EnumPlatformANGLE.fromId(args[i]);
|
||||
if(angle != EnumPlatformANGLE.DEFAULT) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -9,11 +9,10 @@ import org.java_websocket.drafts.Draft_6455;
|
||||
import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -27,51 +26,54 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
class WebSocketPlayClient extends WebSocketClient {
|
||||
class WebSocketClientImpl extends WebSocketClient {
|
||||
|
||||
private static final Draft perMessageDeflateDraft = new Draft_6455(new PerMessageDeflateExtension());
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("WebSocket");
|
||||
protected final DesktopWebSocketClient clientObj;
|
||||
|
||||
WebSocketPlayClient(URI serverUri) {
|
||||
WebSocketClientImpl(DesktopWebSocketClient clientObj, URI serverUri) {
|
||||
super(serverUri, perMessageDeflateDraft);
|
||||
this.clientObj = clientObj;
|
||||
this.setConnectionLostTimeout(15);
|
||||
this.setTcpNoDelay(true);
|
||||
this.connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake arg0) {
|
||||
PlatformNetworking.playConnectState = EnumEaglerConnectionState.CONNECTED;
|
||||
PlatformNetworking.serverRateLimit = EnumServerRateLimit.OK;
|
||||
logger.info("Connection opened: {}", this.uri.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int arg0, String arg1, boolean arg2) {
|
||||
logger.info("Connection closed: {}", this.uri.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception arg0) {
|
||||
logger.error("Exception thrown by websocket \"" + this.getURI().toString() + "\"!");
|
||||
logger.error(arg0);
|
||||
PlatformNetworking.playConnectState = EnumEaglerConnectionState.FAILED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String arg0) {
|
||||
if(arg0.equalsIgnoreCase("BLOCKED")) {
|
||||
logger.error("Reached full IP ratelimit!");
|
||||
PlatformNetworking.serverRateLimit = EnumServerRateLimit.BLOCKED;
|
||||
}else if(arg0.equalsIgnoreCase("LOCKED")) {
|
||||
logger.error("Reached full IP ratelimit lockout!");
|
||||
PlatformNetworking.serverRateLimit = EnumServerRateLimit.LOCKED_OUT;
|
||||
clientObj.playConnectState = EnumEaglerConnectionState.CONNECTED;
|
||||
DesktopWebSocketClient.logger.info("Connection opened: {}", this.uri.toString());
|
||||
synchronized(clientObj.connectOpenMutex) {
|
||||
clientObj.connectOpenMutex.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer arg0) {
|
||||
PlatformNetworking.recievedPlayPacket(arg0.array());
|
||||
public void onClose(int arg0, String arg1, boolean arg2) {
|
||||
DesktopWebSocketClient.logger.info("Connection closed: {}", this.uri.toString());
|
||||
if(clientObj.playConnectState != EnumEaglerConnectionState.FAILED) {
|
||||
clientObj.playConnectState = EnumEaglerConnectionState.CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onError(Exception arg0) {
|
||||
DesktopWebSocketClient.logger.error("Exception thrown by websocket \"" + this.getURI().toString() + "\"!");
|
||||
DesktopWebSocketClient.logger.error(arg0);
|
||||
if(clientObj.playConnectState == EnumEaglerConnectionState.CONNECTING) {
|
||||
clientObj.playConnectState = EnumEaglerConnectionState.FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String arg0) {
|
||||
clientObj.handleString(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer arg0) {
|
||||
clientObj.handleBytes(arg0.array());
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user