mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-27 18:38:14 -05:00
Update #37 - Touch support without userscript, many other feats
This commit is contained in:
2333
sources/lwjgl/java/fi/iki/elonen/NanoHTTPD.java
Normal file
2333
sources/lwjgl/java/fi/iki/elonen/NanoHTTPD.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformScreenRecord {
|
||||
|
||||
public static boolean isSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
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.
|
||||
@ -19,37 +20,44 @@ import java.io.IOException;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class IPacket70SpecialUpdate extends IPacket {
|
||||
public class DesktopWebSocketFrameString implements IWebSocketFrame {
|
||||
|
||||
public static final int OPERATION_UPDATE_CERTIFICATE = 0x69;
|
||||
private final String string;
|
||||
private final long timestamp;
|
||||
|
||||
public int operation;
|
||||
public byte[] updatePacket;
|
||||
|
||||
public IPacket70SpecialUpdate() {
|
||||
}
|
||||
|
||||
public IPacket70SpecialUpdate(int operation, byte[] updatePacket) {
|
||||
this.operation = operation;
|
||||
this.updatePacket = updatePacket;
|
||||
public DesktopWebSocketFrameString(String string) {
|
||||
this.string = string;
|
||||
this.timestamp = PlatformRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
operation = input.read();
|
||||
updatePacket = new byte[input.readUnsignedShort()];
|
||||
input.read(updatePacket);
|
||||
public boolean isString() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
output.write(operation);
|
||||
output.writeShort(updatePacket.length);
|
||||
output.write(updatePacket);
|
||||
public String getString() {
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int packetLength() {
|
||||
return 3 + updatePacket.length;
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,7 @@ public class ClientPlatformSingleplayer {
|
||||
|
||||
private static CrashScreenPopup crashOverlay = null;
|
||||
|
||||
public static void startIntegratedServer() {
|
||||
public static void startIntegratedServer(boolean forceSingleThread) {
|
||||
DesktopIntegratedServer.startIntegratedServer();
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ public class ClientPlatformSingleplayer {
|
||||
if(MemoryConnection.serverToClientQueue.size() == 0) {
|
||||
return null;
|
||||
}else {
|
||||
List<IPCPacketData> ret = new ArrayList(MemoryConnection.serverToClientQueue);
|
||||
List<IPCPacketData> ret = new ArrayList<>(MemoryConnection.serverToClientQueue);
|
||||
MemoryConnection.serverToClientQueue.clear();
|
||||
return ret;
|
||||
}
|
||||
@ -71,6 +71,14 @@ public class ClientPlatformSingleplayer {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSingleThreadModeSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void updateSingleThreadMode() {
|
||||
|
||||
}
|
||||
|
||||
public static void showCrashReportOverlay(String report, int x, int y, int w, int h) {
|
||||
if(crashOverlay == null) {
|
||||
crashOverlay = new CrashScreenPopup();
|
||||
|
@ -2,10 +2,12 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Filesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DesktopClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.lwjgl.MemoryConnection;
|
||||
|
||||
@ -26,8 +28,20 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.internal.lwjgl.MemoryConnection;
|
||||
*/
|
||||
public class ServerPlatformSingleplayer {
|
||||
|
||||
private static IEaglerFilesystem filesystem = null;
|
||||
|
||||
public static void initializeContext() {
|
||||
PlatformFilesystem.initialize();
|
||||
if(filesystem == null) {
|
||||
filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
|
||||
}
|
||||
}
|
||||
|
||||
public static void initializeContextSingleThread(Consumer<IPCPacketData> packetSendCallback) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static IEaglerFilesystem getWorldsDatabase() {
|
||||
return filesystem;
|
||||
}
|
||||
|
||||
public static void sendPacket(IPCPacketData packet) {
|
||||
@ -50,7 +64,7 @@ public class ServerPlatformSingleplayer {
|
||||
if(MemoryConnection.clientToServerQueue.size() == 0) {
|
||||
return null;
|
||||
}else {
|
||||
List<IPCPacketData> ret = new ArrayList(MemoryConnection.clientToServerQueue);
|
||||
List<IPCPacketData> ret = new ArrayList<>(MemoryConnection.clientToServerQueue);
|
||||
MemoryConnection.clientToServerQueue.clear();
|
||||
return ret;
|
||||
}
|
||||
@ -60,4 +74,17 @@ public class ServerPlatformSingleplayer {
|
||||
public static IClientConfigAdapter getClientConfigAdapter() {
|
||||
return DesktopClientConfigAdapter.instance;
|
||||
}
|
||||
|
||||
public static void immediateContinue() {
|
||||
|
||||
}
|
||||
|
||||
public static void platformShutdown() {
|
||||
filesystem = null;
|
||||
}
|
||||
|
||||
public static boolean isSingleThreadMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
*/
|
||||
public class MemoryConnection {
|
||||
|
||||
public static final List<IPCPacketData> clientToServerQueue = new LinkedList();
|
||||
public static final List<IPCPacketData> serverToClientQueue = new LinkedList();
|
||||
public static final List<IPCPacketData> clientToServerQueue = new LinkedList<>();
|
||||
public static final List<IPCPacketData> serverToClientQueue = new LinkedList<>();
|
||||
|
||||
}
|
||||
|
@ -140,9 +140,9 @@ public abstract class CharMatcher implements Predicate<Character> {
|
||||
}
|
||||
|
||||
// Must be in ascending order.
|
||||
private static final String ZEROES = "0\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6"
|
||||
+ "\u0c66\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946\u19d0\u1b50\u1bb0"
|
||||
+ "\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10";
|
||||
private static final String ZEROES = new String(new char[] { '0', 0x0660, 0x06f0, 0x07c0, 0x0966, 0x09e6, 0x0a66,
|
||||
0x0ae6, 0x0b66, 0x0be6, 0x0c66, 0x0ce6, 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x1090, 0x17e0, 0x1810,
|
||||
0x1946, 0x19d0, 0x1b50, 0x1bb0, 0x1c40, 0x1c50, 0xa620, 0xa8d0, 0xa900, 0xaa50, 0xff10 });
|
||||
|
||||
private static final String NINES;
|
||||
static {
|
||||
@ -234,10 +234,10 @@ public abstract class CharMatcher implements Predicate<Character> {
|
||||
* FORMAT, SURROGATE, and PRIVATE_USE according to ICU4J.
|
||||
*/
|
||||
public static final CharMatcher INVISIBLE = new RangesMatcher("CharMatcher.INVISIBLE",
|
||||
("\u0000\u007f\u00ad\u0600\u061c\u06dd\u070f\u1680\u180e\u2000\u2028\u205f\u2066\u2067\u2068"
|
||||
+ "\u2069\u206a\u3000\ud800\ufeff\ufff9\ufffa").toCharArray(),
|
||||
("\u0020\u00a0\u00ad\u0604\u061c\u06dd\u070f\u1680\u180e\u200f\u202f\u2064\u2066\u2067\u2068"
|
||||
+ "\u2069\u206f\u3000\uf8ff\ufeff\ufff9\ufffb").toCharArray());
|
||||
new char[] { 0x0000, 0x007f, 0x00ad, 0x0600, 0x061c, 0x06dd, 0x070f, 0x1680, 0x180e, 0x2000, 0x2028, 0x205f,
|
||||
0x2066, 0x2067, 0x2068, 0x2069, 0x206a, 0x3000, 0xd800, 0xfeff, 0xfff9, 0xfffa },
|
||||
new char[] { 0x0020, 0x00a0, 0x00ad, 0x0604, 0x061c, 0x06dd, 0x070f, 0x1680, 0x180e, 0x200f, 0x202f, 0x2064,
|
||||
0x2066, 0x2067, 0x2068, 0x2069, 0x206f, 0x3000, 0xf8ff, 0xfeff, 0xfff9, 0xfffb });
|
||||
|
||||
private static String showCharacter(char c) {
|
||||
String hex = "0123456789ABCDEF";
|
||||
@ -260,8 +260,8 @@ public abstract class CharMatcher implements Predicate<Character> {
|
||||
* keep it up to date.
|
||||
*/
|
||||
public static final CharMatcher SINGLE_WIDTH = new RangesMatcher("CharMatcher.SINGLE_WIDTH",
|
||||
"\u0000\u05be\u05d0\u05f3\u0600\u0750\u0e00\u1e00\u2100\ufb50\ufe70\uff61".toCharArray(),
|
||||
"\u04f9\u05be\u05ea\u05f4\u06ff\u077f\u0e7f\u20af\u213a\ufdff\ufeff\uffdc".toCharArray());
|
||||
new char[] { 0x0000, 0x05be, 0x05d0, 0x05f3, 0x0600, 0x0750, 0x0e00, 0x1e00, 0x2100, 0xfb50, 0xfe70, 0xff61 },
|
||||
new char[] { 0x04f9, 0x05be, 0x05ea, 0x05f4, 0x06ff, 0x077f, 0x0e7f, 0x20af, 0x213a, 0xfdff, 0xfeff, 0xffdc });
|
||||
|
||||
/** Matches any character. */
|
||||
public static final CharMatcher ANY = new FastMatcher("CharMatcher.ANY") {
|
||||
@ -1474,9 +1474,9 @@ public abstract class CharMatcher implements Predicate<Character> {
|
||||
return description;
|
||||
}
|
||||
|
||||
static final String WHITESPACE_TABLE = "" + "\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000"
|
||||
+ "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680" + "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009"
|
||||
+ "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000";
|
||||
static final String WHITESPACE_TABLE = new String(new char[] { 0x2002, 0x3000, '\r', 0x0085, 0x200A, 0x2005, 0x2000,
|
||||
0x3000, 0x2029, 0x000B, 0x3000, 0x2008, 0x2003, 0x205F, 0x3000, 0x1680, 0x0009, 0x0020, 0x2006, 0x2001,
|
||||
0x202F, 0x00A0, 0x000C, 0x2009, 0x3000, 0x2004, 0x3000, 0x3000, 0x2028, '\n', 0x2007, 0x3000 });
|
||||
static final int WHITESPACE_MULTIPLIER = 1682554634;
|
||||
static final int WHITESPACE_SHIFT = Integer.numberOfLeadingZeros(WHITESPACE_TABLE.length() - 1);
|
||||
|
||||
|
@ -116,6 +116,14 @@ public class Base64 extends BaseNCodec {
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z
|
||||
};
|
||||
|
||||
public static int lookupCharInt(char c) {
|
||||
return c < 123 ? DECODE_TABLE[c] : -1;
|
||||
}
|
||||
|
||||
public static char lookupIntChar(int i) {
|
||||
return (char)STANDARD_ENCODE_TABLE[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 uses 6-bit fields.
|
||||
*/
|
||||
|
@ -0,0 +1,152 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetOtherClientUUIDV4EAG;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.AbstractClientPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
|
||||
/**
|
||||
* 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 ClientUUIDLoadingCache {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("ClientUUIDLoadingCache");
|
||||
|
||||
public static final EaglercraftUUID NULL_UUID = new EaglercraftUUID(0l, 0l);
|
||||
public static final EaglercraftUUID PENDING_UUID = new EaglercraftUUID(0x6969696969696969l, 0x6969696969696969l);
|
||||
public static final EaglercraftUUID VANILLA_UUID = new EaglercraftUUID(0x1DCE015CD384374El, 0x85030A4DE95E5736l);
|
||||
|
||||
/**
|
||||
* For client devs, allows you to get EaglercraftVersion.clientBrandUUID of
|
||||
* other players on a server, to detect other players who also use your client.
|
||||
*
|
||||
* Requires EaglerXBungee 1.3.0 or EaglerXVelocity 1.1.0
|
||||
*
|
||||
* @return NULL_UUID if not found, PENDING_UUID if pending,
|
||||
* VANILLA_UUID if vanilla, or the remote player's
|
||||
* client's EaglercraftVersion.clientBrandUUID
|
||||
*/
|
||||
public static EaglercraftUUID getPlayerClientBrandUUID(EntityPlayer player) {
|
||||
EaglercraftUUID ret = null;
|
||||
if(player instanceof AbstractClientPlayer) {
|
||||
ret = ((AbstractClientPlayer)player).clientBrandUUIDCache;
|
||||
if(ret == null) {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
if(mc != null && mc.thePlayer != null && mc.thePlayer.sendQueue.getEaglerMessageProtocol().ver >= 4) {
|
||||
ret = PENDING_UUID;
|
||||
EaglercraftUUID playerUUID = player.getUniqueID();
|
||||
if(!waitingUUIDs.containsKey(playerUUID) && !evictedUUIDs.containsKey(playerUUID)) {
|
||||
int reqID = ++requestId & 0x3FFF;
|
||||
WaitingLookup newLookup = new WaitingLookup(reqID, playerUUID, EagRuntime.steadyTimeMillis(),
|
||||
(AbstractClientPlayer) player);
|
||||
waitingIDs.put(reqID, newLookup);
|
||||
waitingUUIDs.put(playerUUID, newLookup);
|
||||
mc.thePlayer.sendQueue.sendEaglerMessage(
|
||||
new CPacketGetOtherClientUUIDV4EAG(reqID, newLookup.uuid.msb, newLookup.uuid.lsb));
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if(player instanceof EntityPlayerMP) {
|
||||
ret = ((EntityPlayerMP)player).clientBrandUUID;
|
||||
}
|
||||
if(ret == null) {
|
||||
ret = NULL_UUID;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static final Map<Integer,WaitingLookup> waitingIDs = new HashMap<>();
|
||||
private static final Map<EaglercraftUUID,WaitingLookup> waitingUUIDs = new HashMap<>();
|
||||
private static final Map<EaglercraftUUID,Long> evictedUUIDs = new HashMap<>();
|
||||
|
||||
private static int requestId = 0;
|
||||
private static long lastFlushReq = EagRuntime.steadyTimeMillis();
|
||||
private static long lastFlushEvict = EagRuntime.steadyTimeMillis();
|
||||
|
||||
public static void update() {
|
||||
long timestamp = EagRuntime.steadyTimeMillis();
|
||||
if(timestamp - lastFlushReq > 5000l) {
|
||||
lastFlushReq = timestamp;
|
||||
if(!waitingIDs.isEmpty()) {
|
||||
Iterator<WaitingLookup> itr = waitingIDs.values().iterator();
|
||||
while(itr.hasNext()) {
|
||||
WaitingLookup lookup = itr.next();
|
||||
if(timestamp - lookup.timestamp > 15000l) {
|
||||
itr.remove();
|
||||
waitingUUIDs.remove(lookup.uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(timestamp - lastFlushEvict > 1000l) {
|
||||
lastFlushEvict = timestamp;
|
||||
if(!evictedUUIDs.isEmpty()) {
|
||||
Iterator<Long> evictItr = evictedUUIDs.values().iterator();
|
||||
while(evictItr.hasNext()) {
|
||||
if(timestamp - evictItr.next().longValue() > 3000l) {
|
||||
evictItr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void flushRequestCache() {
|
||||
waitingIDs.clear();
|
||||
waitingUUIDs.clear();
|
||||
evictedUUIDs.clear();
|
||||
}
|
||||
|
||||
public static void handleResponse(int requestId, EaglercraftUUID clientId) {
|
||||
WaitingLookup lookup = waitingIDs.remove(requestId);
|
||||
if(lookup != null) {
|
||||
lookup.player.clientBrandUUIDCache = clientId;
|
||||
waitingUUIDs.remove(lookup.uuid);
|
||||
}else {
|
||||
logger.warn("Unsolicited client brand UUID lookup response #{} recieved! (Brand UUID: {})", requestId, clientId);
|
||||
}
|
||||
}
|
||||
|
||||
public static void evict(EaglercraftUUID clientId) {
|
||||
evictedUUIDs.put(clientId, Long.valueOf(EagRuntime.steadyTimeMillis()));
|
||||
WaitingLookup lk = waitingUUIDs.remove(clientId);
|
||||
if(lk != null) {
|
||||
waitingIDs.remove(lk.reqID);
|
||||
}
|
||||
}
|
||||
|
||||
private static class WaitingLookup {
|
||||
|
||||
private final int reqID;
|
||||
private final EaglercraftUUID uuid;
|
||||
private final long timestamp;
|
||||
private final AbstractClientPlayer player;
|
||||
|
||||
public WaitingLookup(int reqID, EaglercraftUUID uuid, long timestamp, AbstractClientPlayer player) {
|
||||
this.reqID = reqID;
|
||||
this.uuid = uuid;
|
||||
this.timestamp = timestamp;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
public class Display {
|
||||
|
||||
private static long lastSwap = 0l;
|
||||
private static long lastDPIUpdate = -250l;
|
||||
private static float cacheDPI = 1.0f;
|
||||
|
||||
public static int getWidth() {
|
||||
return PlatformInput.getWindowWidth();
|
||||
@ -29,6 +31,22 @@ public class Display {
|
||||
return PlatformInput.getWindowHeight();
|
||||
}
|
||||
|
||||
public static int getVisualViewportX() {
|
||||
return PlatformInput.getVisualViewportX();
|
||||
}
|
||||
|
||||
public static int getVisualViewportY() {
|
||||
return PlatformInput.getVisualViewportY();
|
||||
}
|
||||
|
||||
public static int getVisualViewportW() {
|
||||
return PlatformInput.getVisualViewportW();
|
||||
}
|
||||
|
||||
public static int getVisualViewportH() {
|
||||
return PlatformInput.getVisualViewportH();
|
||||
}
|
||||
|
||||
public static boolean isActive() {
|
||||
return PlatformInput.getWindowFocused();
|
||||
}
|
||||
@ -61,24 +79,32 @@ public class Display {
|
||||
boolean limitFPS = limitFramerate > 0 && limitFramerate < 1000;
|
||||
|
||||
if(limitFPS) {
|
||||
long millis = System.currentTimeMillis();
|
||||
long millis = EagRuntime.steadyTimeMillis();
|
||||
long frameMillis = (1000l / limitFramerate) - (millis - lastSwap);
|
||||
if(frameMillis > 0l) {
|
||||
EagUtils.sleep(frameMillis);
|
||||
}
|
||||
}
|
||||
|
||||
lastSwap = System.currentTimeMillis();
|
||||
lastSwap = EagRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
public static boolean contextLost() {
|
||||
return PlatformInput.contextLost();
|
||||
}
|
||||
|
||||
|
||||
public static boolean wasResized() {
|
||||
return PlatformInput.wasResized();
|
||||
}
|
||||
|
||||
public static boolean wasVisualViewportResized() {
|
||||
return PlatformInput.wasVisualViewportResized();
|
||||
}
|
||||
|
||||
public static boolean supportsFullscreen() {
|
||||
return PlatformInput.supportsFullscreen();
|
||||
}
|
||||
|
||||
public static boolean isFullscreen() {
|
||||
return PlatformInput.isFullscreen();
|
||||
}
|
||||
@ -87,4 +113,13 @@ public class Display {
|
||||
PlatformInput.toggleFullscreen();
|
||||
}
|
||||
|
||||
public static float getDPI() {
|
||||
long millis = EagRuntime.steadyTimeMillis();
|
||||
if(millis - lastDPIUpdate > 250l) {
|
||||
lastDPIUpdate = millis;
|
||||
cacheDPI = PlatformInput.getDPI();
|
||||
}
|
||||
return cacheDPI;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,17 +3,16 @@ package net.lax1dude.eaglercraft.v1_8;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.io.InputStreamReader;
|
||||
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 java.nio.charset.StandardCharsets;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EaglerMissingResourceException;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformANGLE;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformAgent;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformOS;
|
||||
@ -26,6 +25,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
|
||||
import net.lax1dude.eaglercraft.v1_8.recording.ScreenRecordingController;
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
|
||||
|
||||
/**
|
||||
@ -70,6 +70,8 @@ public class EagRuntime {
|
||||
UpdateService.initialize();
|
||||
EaglerXBungeeVersion.initialize();
|
||||
EaglercraftGPU.warmUpCache();
|
||||
ScreenRecordingController.initialize();
|
||||
PlatformRuntime.postCreate();
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
@ -119,11 +121,23 @@ public class EagRuntime {
|
||||
public static void freeFloatBuffer(FloatBuffer byteBuffer) {
|
||||
PlatformRuntime.freeFloatBuffer(byteBuffer);
|
||||
}
|
||||
|
||||
|
||||
public static boolean getResourceExists(String path) {
|
||||
return PlatformAssets.getResourceExists(path);
|
||||
}
|
||||
|
||||
public static byte[] getResourceBytes(String path) {
|
||||
return PlatformAssets.getResourceBytes(path);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] getRequiredResourceBytes(String path) {
|
||||
byte[] ret = PlatformAssets.getResourceBytes(path);
|
||||
if(ret == null) {
|
||||
throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static InputStream getResourceStream(String path) {
|
||||
byte[] b = PlatformAssets.getResourceBytes(path);
|
||||
if(b != null) {
|
||||
@ -132,24 +146,41 @@ public class EagRuntime {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static InputStream getRequiredResourceStream(String path) {
|
||||
byte[] ret = PlatformAssets.getResourceBytes(path);
|
||||
if(ret == null) {
|
||||
throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
|
||||
}
|
||||
return new EaglerInputStream(ret);
|
||||
}
|
||||
|
||||
public static String getResourceString(String path) {
|
||||
byte[] bytes = PlatformAssets.getResourceBytes(path);
|
||||
return bytes != null ? new String(bytes, StandardCharsets.UTF_8) : null;
|
||||
}
|
||||
|
||||
|
||||
public static String getRequiredResourceString(String path) {
|
||||
byte[] ret = PlatformAssets.getResourceBytes(path);
|
||||
if(ret == null) {
|
||||
throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
|
||||
}
|
||||
return new String(ret, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static List<String> getResourceLines(String path) {
|
||||
byte[] bytes = PlatformAssets.getResourceBytes(path);
|
||||
if(bytes != null) {
|
||||
List<String> ret = new ArrayList();
|
||||
List<String> ret = new ArrayList<>();
|
||||
try {
|
||||
BufferedReader rd = new BufferedReader(new StringReader(path));
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(new EaglerInputStream(bytes), StandardCharsets.UTF_8));
|
||||
String s;
|
||||
while((s = rd.readLine()) != null) {
|
||||
ret.add(s);
|
||||
}
|
||||
}catch(IOException ex) {
|
||||
// ??
|
||||
return null;
|
||||
}
|
||||
return ret;
|
||||
}else {
|
||||
@ -157,6 +188,14 @@ public class EagRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getRequiredResourceLines(String path) {
|
||||
List<String> ret = getResourceLines(path);
|
||||
if(ret == null) {
|
||||
throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void debugPrintStackTraceToSTDERR(Throwable t) {
|
||||
debugPrintStackTraceToSTDERR0("", t);
|
||||
Throwable c = t.getCause();
|
||||
@ -180,7 +219,7 @@ public class EagRuntime {
|
||||
}
|
||||
|
||||
public static String[] getStackTraceElements(Throwable t) {
|
||||
List<String> lst = new ArrayList();
|
||||
List<String> lst = new ArrayList<>();
|
||||
PlatformRuntime.getStackTrace(t, (s) -> {
|
||||
lst.add(s);
|
||||
});
|
||||
@ -222,17 +261,23 @@ public class EagRuntime {
|
||||
PlatformRuntime.exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note to skids: This doesn't do anything in javascript runtime!
|
||||
*/
|
||||
public static long maxMemory() {
|
||||
return PlatformRuntime.maxMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note to skids: This doesn't do anything in TeaVM runtime!
|
||||
* Note to skids: This doesn't do anything in javascript runtime!
|
||||
*/
|
||||
public static long totalMemory() {
|
||||
return PlatformRuntime.totalMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note to skids: This doesn't do anything in javascript runtime!
|
||||
*/
|
||||
public static long freeMemory() {
|
||||
return PlatformRuntime.freeMemory();
|
||||
}
|
||||
@ -289,18 +334,6 @@ public class EagRuntime {
|
||||
return PlatformRuntime.getClientConfigAdapter();
|
||||
}
|
||||
|
||||
public static String getRecText() {
|
||||
return PlatformRuntime.getRecText();
|
||||
}
|
||||
|
||||
public static void toggleRec() {
|
||||
PlatformRuntime.toggleRec();
|
||||
}
|
||||
|
||||
public static boolean recSupported() {
|
||||
return PlatformRuntime.recSupported();
|
||||
}
|
||||
|
||||
public static void openCreditsPopup(String text) {
|
||||
PlatformApplication.openCreditsPopup(text);
|
||||
}
|
||||
@ -317,16 +350,24 @@ public class EagRuntime {
|
||||
PlatformApplication.showDebugConsole();
|
||||
}
|
||||
|
||||
public static Calendar getLocaleCalendar() {
|
||||
return Calendar.getInstance(); //TODO: fix teavm calendar's time zone offset
|
||||
}
|
||||
|
||||
public static <T extends DateFormat> T fixDateFormat(T input) {
|
||||
input.setCalendar(getLocaleCalendar());
|
||||
return input;
|
||||
public static void setDisplayBootMenuNextRefresh(boolean en) {
|
||||
PlatformRuntime.setDisplayBootMenuNextRefresh(en);
|
||||
}
|
||||
|
||||
public static void setMCServerWindowGlobal(String url) {
|
||||
PlatformApplication.setMCServerWindowGlobal(url);
|
||||
}
|
||||
|
||||
public static long steadyTimeMillis() {
|
||||
return PlatformRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
public static long nanoTime() {
|
||||
return PlatformRuntime.nanoTime();
|
||||
}
|
||||
|
||||
public static void immediateContinue() {
|
||||
PlatformRuntime.immediateContinue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
@ -85,4 +86,12 @@ public class EagUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static EaglercraftUUID makeClientBrandUUID(String name) {
|
||||
return EaglercraftUUID.nameUUIDFromBytes(("EaglercraftXClient:" + name).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static EaglercraftUUID makeClientBrandUUIDLegacy(String name) {
|
||||
return EaglercraftUUID.nameUUIDFromBytes(("EaglercraftXClientOld:" + name).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,6 +74,11 @@ public class EaglerOutputStream extends OutputStream {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void skipBytes(int num) {
|
||||
ensureCapacity(count + num);
|
||||
count += num;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
|
@ -28,10 +28,7 @@ public class EaglerXBungeeVersion {
|
||||
private static String pluginFilename = null;
|
||||
|
||||
public static void initialize() {
|
||||
String pluginVersionJson = EagRuntime.getResourceString("plugin_version.json");
|
||||
if(pluginVersionJson == null) {
|
||||
throw new RuntimeException("File \"plugin_version.json\" is missing in the epk!");
|
||||
}
|
||||
String pluginVersionJson = EagRuntime.getRequiredResourceString("plugin_version.json");
|
||||
JSONObject json = new JSONObject(pluginVersionJson);
|
||||
pluginName = json.getString("pluginName");
|
||||
pluginVersion = json.getString("pluginVersion");
|
||||
@ -76,11 +73,7 @@ public class EaglerXBungeeVersion {
|
||||
}
|
||||
|
||||
public static byte[] getPluginDownload() {
|
||||
byte[] ret = EagRuntime.getResourceBytes(pluginFileEPK);
|
||||
if(ret == null) {
|
||||
throw new RuntimeException("File \"" + pluginFileEPK + "\" is missing in the epk!");
|
||||
}
|
||||
return ret;
|
||||
return EagRuntime.getRequiredResourceBytes(pluginFileEPK);
|
||||
}
|
||||
|
||||
public static void startPluginDownload() {
|
||||
|
@ -130,10 +130,10 @@ public class EaglercraftSoundManager {
|
||||
settings.getSoundLevel(SoundCategory.RECORDS), settings.getSoundLevel(SoundCategory.WEATHER),
|
||||
settings.getSoundLevel(SoundCategory.BLOCKS), settings.getSoundLevel(SoundCategory.MOBS),
|
||||
settings.getSoundLevel(SoundCategory.ANIMALS), settings.getSoundLevel(SoundCategory.PLAYERS),
|
||||
settings.getSoundLevel(SoundCategory.AMBIENT), settings.getSoundLevel(SoundCategory.VOICE)
|
||||
settings.getSoundLevel(SoundCategory.AMBIENT)
|
||||
};
|
||||
activeSounds = new LinkedList();
|
||||
queuedSounds = new LinkedList();
|
||||
activeSounds = new LinkedList<>();
|
||||
queuedSounds = new LinkedList<>();
|
||||
}
|
||||
|
||||
public void unloadSoundSystem() {
|
||||
|
@ -21,6 +21,8 @@ public class EaglercraftUUID implements Comparable<EaglercraftUUID> {
|
||||
|
||||
public final long msb;
|
||||
public final long lsb;
|
||||
private int hash = 0;
|
||||
private boolean hasHash;
|
||||
|
||||
public EaglercraftUUID(long msb, long lsb) {
|
||||
this.msb = msb;
|
||||
@ -125,13 +127,21 @@ public class EaglercraftUUID implements Comparable<EaglercraftUUID> {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long hilo = msb ^ lsb;
|
||||
return ((int) (hilo >> 32)) ^ (int) hilo;
|
||||
if(hash == 0 && !hasHash) {
|
||||
long hilo = msb ^ lsb;
|
||||
hash = ((int) (hilo >> 32)) ^ (int) hilo;
|
||||
hasHash = true;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof EaglercraftUUID) && ((EaglercraftUUID) o).lsb == lsb && ((EaglercraftUUID) o).msb == msb;
|
||||
if(!(o instanceof EaglercraftUUID)) return false;
|
||||
EaglercraftUUID oo = (EaglercraftUUID)o;
|
||||
return (hasHash && oo.hasHash)
|
||||
? (hash == oo.hash && msb == oo.msb && lsb == oo.lsb)
|
||||
: (msb == oo.msb && lsb == oo.lsb);
|
||||
}
|
||||
|
||||
public long getMostSignificantBits() {
|
||||
|
@ -10,7 +10,7 @@ public class EaglercraftVersion {
|
||||
/// Customize these to fit your fork:
|
||||
|
||||
public static final String projectForkName = "EaglercraftX";
|
||||
public static final String projectForkVersion = "u36";
|
||||
public static final String projectForkVersion = "u37";
|
||||
public static final String projectForkVendor = "lax1dude";
|
||||
|
||||
public static final String projectForkURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8";
|
||||
@ -20,7 +20,7 @@ public class EaglercraftVersion {
|
||||
public static final String projectOriginName = "EaglercraftX";
|
||||
public static final String projectOriginAuthor = "lax1dude";
|
||||
public static final String projectOriginRevision = "1.8";
|
||||
public static final String projectOriginVersion = "u36";
|
||||
public static final String projectOriginVersion = "u37";
|
||||
|
||||
public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace
|
||||
|
||||
@ -31,7 +31,7 @@ public class EaglercraftVersion {
|
||||
public static final boolean enableUpdateService = true;
|
||||
|
||||
public static final String updateBundlePackageName = "net.lax1dude.eaglercraft.v1_8.client";
|
||||
public static final int updateBundlePackageVersionInt = 36;
|
||||
public static final int updateBundlePackageVersionInt = 37;
|
||||
|
||||
public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName;
|
||||
|
||||
@ -40,6 +40,13 @@ public class EaglercraftVersion {
|
||||
|
||||
|
||||
|
||||
// Client brand identification system configuration
|
||||
|
||||
public static final EaglercraftUUID clientBrandUUID = EagUtils.makeClientBrandUUID(projectForkName);
|
||||
|
||||
public static final EaglercraftUUID legacyClientUUIDInSharedWorld = EagUtils.makeClientBrandUUIDLegacy(projectOriginName);
|
||||
|
||||
|
||||
// Miscellaneous variables:
|
||||
|
||||
public static final String mainMenuStringA = "Minecraft 1.8.8";
|
||||
|
158
sources/main/java/net/lax1dude/eaglercraft/v1_8/Filesystem.java
Normal file
158
sources/main/java/net/lax1dude/eaglercraft/v1_8/Filesystem.java
Normal file
@ -0,0 +1,158 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.RamdiskFilesystemImpl;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
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 Filesystem {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PlatformFilesystem");
|
||||
|
||||
private static final Map<String,FilesystemHandle> openFilesystems = new HashMap<>();
|
||||
|
||||
public static IEaglerFilesystem getHandleFor(String dbName) {
|
||||
FilesystemHandle handle = openFilesystems.get(dbName);
|
||||
if(handle != null) {
|
||||
++handle.refCount;
|
||||
return new FilesystemHandleWrapper(handle);
|
||||
}
|
||||
IEaglerFilesystem handleImpl = null;
|
||||
if(!EagRuntime.getConfiguration().isRamdiskMode()) {
|
||||
handleImpl = PlatformFilesystem.initializePersist(dbName);
|
||||
}
|
||||
if(handleImpl == null) {
|
||||
handleImpl = new RamdiskFilesystemImpl(dbName);
|
||||
}
|
||||
if(handleImpl.isRamdisk()) {
|
||||
logger.warn("Using RAMDisk filesystem for database \"{}\", data will not be saved to local storage!", dbName);
|
||||
}
|
||||
handle = new FilesystemHandle(handleImpl);
|
||||
openFilesystems.put(dbName, handle);
|
||||
return new FilesystemHandleWrapper(handle);
|
||||
}
|
||||
|
||||
public static void closeAllHandles() {
|
||||
for(FilesystemHandle handle : openFilesystems.values()) {
|
||||
handle.refCount = 0;
|
||||
handle.handle.closeHandle();
|
||||
}
|
||||
openFilesystems.clear();
|
||||
}
|
||||
|
||||
private static class FilesystemHandle {
|
||||
|
||||
private final IEaglerFilesystem handle;
|
||||
private int refCount;
|
||||
|
||||
private FilesystemHandle(IEaglerFilesystem handle) {
|
||||
this.handle = handle;
|
||||
this.refCount = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class FilesystemHandleWrapper implements IEaglerFilesystem {
|
||||
|
||||
private final FilesystemHandle handle;
|
||||
private final IEaglerFilesystem handleImpl;
|
||||
private boolean closed;
|
||||
|
||||
private FilesystemHandleWrapper(FilesystemHandle handle) {
|
||||
this.handle = handle;
|
||||
this.handleImpl = handle.handle;
|
||||
this.closed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilesystemName() {
|
||||
return handleImpl.getFilesystemName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalDBName() {
|
||||
return handleImpl.getInternalDBName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRamdisk() {
|
||||
return handleImpl.isRamdisk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerDelete(String pathName) {
|
||||
return handleImpl.eaglerDelete(pathName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer eaglerRead(String pathName) {
|
||||
return handleImpl.eaglerRead(pathName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eaglerWrite(String pathName, ByteBuffer data) {
|
||||
handleImpl.eaglerWrite(pathName, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerExists(String pathName) {
|
||||
return handleImpl.eaglerExists(pathName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerMove(String pathNameOld, String pathNameNew) {
|
||||
return handleImpl.eaglerMove(pathNameOld, pathNameNew);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int eaglerCopy(String pathNameOld, String pathNameNew) {
|
||||
return handleImpl.eaglerCopy(pathNameOld, pathNameNew);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int eaglerSize(String pathName) {
|
||||
return handleImpl.eaglerSize(pathName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
|
||||
handleImpl.eaglerIterate(pathName, itr, recursive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHandle() {
|
||||
if(!closed && handle.refCount > 0) {
|
||||
closed = true;
|
||||
--handle.refCount;
|
||||
if(handle.refCount <= 0) {
|
||||
logger.info("Releasing filesystem handle for: \"{}\"", handleImpl.getFilesystemName());
|
||||
handleImpl.closeHandle();
|
||||
openFilesystems.remove(handleImpl.getFilesystemName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
115
sources/main/java/net/lax1dude/eaglercraft/v1_8/Gamepad.java
Normal file
115
sources/main/java/net/lax1dude/eaglercraft/v1_8/Gamepad.java
Normal file
@ -0,0 +1,115 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.GamepadConstants;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
|
||||
/**
|
||||
* 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 Gamepad {
|
||||
|
||||
private static final boolean[] buttonsLastState = new boolean[24];
|
||||
private static final List<VirtualButtonEvent> buttonEvents = new LinkedList<>();
|
||||
private static VirtualButtonEvent currentVEvent = null;
|
||||
|
||||
private static class VirtualButtonEvent {
|
||||
|
||||
private final int button;
|
||||
private final boolean state;
|
||||
|
||||
public VirtualButtonEvent(int button, boolean state) {
|
||||
this.button = button;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int getValidDeviceCount() {
|
||||
return PlatformInput.gamepadGetValidDeviceCount();
|
||||
}
|
||||
|
||||
public static String getDeviceName(int deviceId) {
|
||||
return PlatformInput.gamepadGetDeviceName(deviceId);
|
||||
}
|
||||
|
||||
public static void setSelectedDevice(int deviceId) {
|
||||
PlatformInput.gamepadSetSelectedDevice(deviceId);
|
||||
}
|
||||
|
||||
public static void update() {
|
||||
PlatformInput.gamepadUpdate();
|
||||
if(isValid()) {
|
||||
for(int i = 0; i < buttonsLastState.length; ++i) {
|
||||
boolean b = PlatformInput.gamepadGetButtonState(i);
|
||||
if(b != buttonsLastState[i]) {
|
||||
buttonsLastState[i] = b;
|
||||
buttonEvents.add(new VirtualButtonEvent(i, b));
|
||||
if(buttonEvents.size() > 64) {
|
||||
buttonEvents.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
for(int i = 0; i < buttonsLastState.length; ++i) {
|
||||
buttonsLastState[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean next() {
|
||||
currentVEvent = null;
|
||||
return !buttonEvents.isEmpty() && (currentVEvent = buttonEvents.remove(0)) != null;
|
||||
}
|
||||
|
||||
public static int getEventButton() {
|
||||
return currentVEvent != null ? currentVEvent.button : -1;
|
||||
}
|
||||
|
||||
public static boolean getEventButtonState() {
|
||||
return currentVEvent != null ? currentVEvent.state : false;
|
||||
}
|
||||
|
||||
public static boolean isValid() {
|
||||
return PlatformInput.gamepadIsValid();
|
||||
}
|
||||
|
||||
public static String getName() {
|
||||
return PlatformInput.gamepadGetName();
|
||||
}
|
||||
|
||||
public static boolean getButtonState(int button) {
|
||||
return PlatformInput.gamepadGetButtonState(button);
|
||||
}
|
||||
|
||||
public static String getButtonName(int button) {
|
||||
return GamepadConstants.getButtonName(button);
|
||||
}
|
||||
|
||||
public static float getAxis(int axis) {
|
||||
return PlatformInput.gamepadGetAxis(axis);
|
||||
}
|
||||
|
||||
public static String getAxisName(int button) {
|
||||
return GamepadConstants.getAxisName(button);
|
||||
}
|
||||
|
||||
public static void clearEventBuffer() {
|
||||
buttonEvents.clear();
|
||||
}
|
||||
|
||||
}
|
54
sources/main/java/net/lax1dude/eaglercraft/v1_8/HashKey.java
Normal file
54
sources/main/java/net/lax1dude/eaglercraft/v1_8/HashKey.java
Normal file
@ -0,0 +1,54 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 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 HashKey {
|
||||
|
||||
public final byte[] key;
|
||||
public final int hash;
|
||||
|
||||
public HashKey(byte[] key, int hashCode) {
|
||||
this.key = key;
|
||||
this.hash = hashCode;
|
||||
}
|
||||
|
||||
public HashKey(byte[] key) {
|
||||
this.key = key;
|
||||
this.hash = Arrays.hashCode(key);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
return new HashKey(key, hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || !(obj instanceof HashKey))
|
||||
return false;
|
||||
HashKey other = (HashKey) obj;
|
||||
return hash == other.hash && Arrays.equals(key, other.key);
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,7 @@ public class IOUtils {
|
||||
return Arrays.asList(
|
||||
new String(((EaglerInputStream) parInputStream).getAsArray(), charset).split("(\\r\\n|\\n|\\r)"));
|
||||
}else {
|
||||
List<String> ret = new ArrayList();
|
||||
List<String> ret = new ArrayList<>();
|
||||
try(InputStream is = parInputStream) {
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, charset));
|
||||
String s;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumFireKeyboardEvent;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.KeyboardConstants;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
|
||||
@ -60,4 +61,8 @@ public class Keyboard {
|
||||
return PlatformInput.keyboardIsRepeatEvent();
|
||||
}
|
||||
|
||||
public static void fireEvent(EnumFireKeyboardEvent eventType, int eagKey, char keyChar) {
|
||||
PlatformInput.keyboardFireEvent(eventType, eagKey, keyChar);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumFireMouseEvent;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
|
||||
/**
|
||||
@ -92,6 +93,22 @@ public class Mouse {
|
||||
return PlatformInput.isMouseGrabbed();
|
||||
}
|
||||
|
||||
public static boolean isMouseGrabSupported() {
|
||||
return PlatformInput.mouseGrabSupported();
|
||||
}
|
||||
|
||||
public static void fireMoveEvent(EnumFireMouseEvent eventType, int posX, int posY) {
|
||||
PlatformInput.mouseFireMoveEvent(eventType, posX, posY);
|
||||
}
|
||||
|
||||
public static void fireButtonEvent(EnumFireMouseEvent eventType, int posX, int posY, int button) {
|
||||
PlatformInput.mouseFireButtonEvent(eventType, posX, posY, button);
|
||||
}
|
||||
|
||||
public static void fireWheelEvent(EnumFireMouseEvent eventType, int posX, int posY, float wheel) {
|
||||
PlatformInput.mouseFireWheelEvent(eventType, posX, posY, wheel);
|
||||
}
|
||||
|
||||
private static int customCursorCounter = 0;
|
||||
private static EnumCursorType currentCursorType = EnumCursorType.DEFAULT;
|
||||
|
||||
|
@ -0,0 +1,257 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
|
||||
import net.lax1dude.eaglercraft.v1_8.profile.EaglerSkinTexture;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketCustomizePauseMenuV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.PacketImageData;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
/**
|
||||
* 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 PauseMenuCustomizeState {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("PauseMenuCustomizeState");
|
||||
|
||||
public static ResourceLocation icon_title_L;
|
||||
public static float icon_title_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_title_R;
|
||||
public static float icon_title_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_backToGame_L;
|
||||
public static float icon_backToGame_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_backToGame_R;
|
||||
public static float icon_backToGame_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_achievements_L;
|
||||
public static float icon_achievements_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_achievements_R;
|
||||
public static float icon_achievements_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_statistics_L;
|
||||
public static float icon_statistics_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_statistics_R;
|
||||
public static float icon_statistics_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_serverInfo_L;
|
||||
public static float icon_serverInfo_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_serverInfo_R;
|
||||
public static float icon_serverInfo_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_options_L;
|
||||
public static float icon_options_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_options_R;
|
||||
public static float icon_options_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_discord_L;
|
||||
public static float icon_discord_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_discord_R;
|
||||
public static float icon_discord_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_disconnect_L;
|
||||
public static float icon_disconnect_L_aspect = 1.0f;
|
||||
public static ResourceLocation icon_disconnect_R;
|
||||
public static float icon_disconnect_R_aspect = 1.0f;
|
||||
public static ResourceLocation icon_background_pause;
|
||||
public static float icon_background_pause_aspect = 1.0f;
|
||||
public static ResourceLocation icon_background_all;
|
||||
public static float icon_background_all_aspect = 1.0f;
|
||||
public static ResourceLocation icon_watermark_pause;
|
||||
public static float icon_watermark_pause_aspect = 1.0f;
|
||||
public static ResourceLocation icon_watermark_all;
|
||||
public static float icon_watermark_all_aspect = 1.0f;
|
||||
|
||||
public static final int SERVER_INFO_MODE_NONE = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_NONE;
|
||||
public static final int SERVER_INFO_MODE_EXTERNAL_URL = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_EXTERNAL_URL;
|
||||
public static final int SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP;
|
||||
public static final int SERVER_INFO_MODE_SHOW_EMBED_OVER_WS = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_SHOW_EMBED_OVER_WS;
|
||||
|
||||
public static final int SERVER_INFO_EMBED_PERMS_JAVASCRIPT = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_EMBED_PERMS_JAVASCRIPT;
|
||||
public static final int SERVER_INFO_EMBED_PERMS_MESSAGE_API = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_EMBED_PERMS_MESSAGE_API;
|
||||
public static final int SERVER_INFO_EMBED_PERMS_STRICT_CSP = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_EMBED_PERMS_STRICT_CSP;
|
||||
|
||||
public static final int DISCORD_MODE_NONE = SPacketCustomizePauseMenuV4EAG.DISCORD_MODE_NONE;
|
||||
public static final int DISCORD_MODE_INVITE_URL = SPacketCustomizePauseMenuV4EAG.DISCORD_MODE_INVITE_URL;
|
||||
|
||||
public static int serverInfoMode;
|
||||
public static int serverInfoEmbedPerms = SERVER_INFO_EMBED_PERMS_STRICT_CSP;
|
||||
public static String serverInfoEmbedTitle;
|
||||
public static String serverInfoButtonText;
|
||||
public static String serverInfoURL;
|
||||
public static byte[] serverInfoHash;
|
||||
|
||||
public static int discordButtonMode;
|
||||
public static String discordButtonText;
|
||||
public static String discordInviteURL;
|
||||
|
||||
private static final List<PauseMenuSprite> toFree = new ArrayList<>();
|
||||
|
||||
private static int textureId = 0;
|
||||
|
||||
private static class PauseMenuSprite {
|
||||
|
||||
private final ResourceLocation loc;
|
||||
private final EaglerSkinTexture tex;
|
||||
|
||||
public PauseMenuSprite(EaglerSkinTexture tex) {
|
||||
this.loc = newLoc();
|
||||
this.tex = tex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void loadPacket(SPacketCustomizePauseMenuV4EAG packet) {
|
||||
reset();
|
||||
|
||||
serverInfoMode = packet.serverInfoMode;
|
||||
switch(packet.serverInfoMode) {
|
||||
case SERVER_INFO_MODE_NONE:
|
||||
default:
|
||||
serverInfoButtonText = null;
|
||||
serverInfoURL = null;
|
||||
serverInfoHash = null;
|
||||
break;
|
||||
case SERVER_INFO_MODE_EXTERNAL_URL:
|
||||
serverInfoButtonText = packet.serverInfoButtonText;
|
||||
serverInfoURL = packet.serverInfoURL;
|
||||
break;
|
||||
case SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP:
|
||||
serverInfoButtonText = packet.serverInfoButtonText;
|
||||
serverInfoEmbedPerms = packet.serverInfoEmbedPerms;
|
||||
serverInfoURL = packet.serverInfoURL;
|
||||
serverInfoEmbedTitle = packet.serverInfoEmbedTitle;
|
||||
break;
|
||||
case SERVER_INFO_MODE_SHOW_EMBED_OVER_WS:
|
||||
serverInfoButtonText = packet.serverInfoButtonText;
|
||||
serverInfoEmbedPerms = packet.serverInfoEmbedPerms;
|
||||
serverInfoHash = packet.serverInfoHash;
|
||||
serverInfoEmbedTitle = packet.serverInfoEmbedTitle;
|
||||
break;
|
||||
}
|
||||
|
||||
discordButtonMode = packet.discordButtonMode;
|
||||
switch(packet.discordButtonMode) {
|
||||
case DISCORD_MODE_NONE:
|
||||
default:
|
||||
discordButtonText = null;
|
||||
serverInfoURL = null;
|
||||
serverInfoHash = null;
|
||||
break;
|
||||
case DISCORD_MODE_INVITE_URL:
|
||||
discordButtonText = packet.discordButtonText;
|
||||
discordInviteURL = packet.discordInviteURL;
|
||||
break;
|
||||
}
|
||||
|
||||
if(packet.imageMappings != null) {
|
||||
Map<Integer, PauseMenuSprite> spriteCache = new HashMap<>();
|
||||
icon_title_L = cacheLoadHelperFunction("icon_title_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_title_L_aspect = a);
|
||||
icon_title_R = cacheLoadHelperFunction("icon_title_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_title_R_aspect = a);
|
||||
icon_backToGame_L = cacheLoadHelperFunction("icon_backToGame_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_backToGame_L_aspect = a);
|
||||
icon_backToGame_R = cacheLoadHelperFunction("icon_backToGame_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_backToGame_R_aspect = a);
|
||||
icon_achievements_L = cacheLoadHelperFunction("icon_achievements_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_achievements_L_aspect = a);
|
||||
icon_achievements_R = cacheLoadHelperFunction("icon_achievements_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_achievements_R_aspect = a);
|
||||
icon_statistics_L = cacheLoadHelperFunction("icon_statistics_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_statistics_L_aspect = a);
|
||||
icon_statistics_R = cacheLoadHelperFunction("icon_statistics_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_statistics_R_aspect = a);
|
||||
icon_serverInfo_L = cacheLoadHelperFunction("icon_serverInfo_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_serverInfo_L_aspect = a);
|
||||
icon_serverInfo_R = cacheLoadHelperFunction("icon_serverInfo_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_serverInfo_R_aspect = a);
|
||||
icon_options_L = cacheLoadHelperFunction("icon_options_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_options_L_aspect = a);
|
||||
icon_options_R = cacheLoadHelperFunction("icon_options_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_options_R_aspect = a);
|
||||
icon_discord_L = cacheLoadHelperFunction("icon_discord_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_discord_L_aspect = a);
|
||||
icon_discord_R = cacheLoadHelperFunction("icon_discord_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_discord_R_aspect = a);
|
||||
icon_disconnect_L = cacheLoadHelperFunction("icon_disconnect_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_disconnect_L_aspect = a);
|
||||
icon_disconnect_R = cacheLoadHelperFunction("icon_disconnect_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_disconnect_R_aspect = a);
|
||||
icon_background_pause = cacheLoadHelperFunction("icon_background_pause", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_background_pause_aspect = a);
|
||||
icon_background_all = cacheLoadHelperFunction("icon_background_all", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_background_all_aspect = a);
|
||||
icon_watermark_pause = cacheLoadHelperFunction("icon_watermark_pause", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_watermark_pause_aspect = a);
|
||||
icon_watermark_all = cacheLoadHelperFunction("icon_watermark_all", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_watermark_all_aspect = a);
|
||||
}
|
||||
}
|
||||
|
||||
private static ResourceLocation cacheLoadHelperFunction(String name, Map<String, Integer> lookup,
|
||||
Map<Integer, PauseMenuSprite> spriteCache,
|
||||
List<PacketImageData> sourceData, Consumer<Float> aspectCB) {
|
||||
Integer i = lookup.get(name);
|
||||
if(i == null) {
|
||||
return null;
|
||||
}
|
||||
PauseMenuSprite ret = spriteCache.get(i);
|
||||
if(ret != null) {
|
||||
if(name.startsWith("icon_background_") && ImageData.isNPOTStatic(ret.tex.getWidth(), ret.tex.getHeight())) {
|
||||
logger.warn("An NPOT (non-power-of-two) texture was used for \"{}\", this texture's width and height must be powers of two for this texture to display properly on all hardware");
|
||||
}
|
||||
aspectCB.accept((float)ret.tex.getWidth() / ret.tex.getHeight());
|
||||
return ret.loc;
|
||||
}
|
||||
int ii = i.intValue();
|
||||
if(ii < 0 || ii >= sourceData.size()) {
|
||||
return null;
|
||||
}
|
||||
PacketImageData data = sourceData.get(ii);
|
||||
ret = new PauseMenuSprite(new EaglerSkinTexture(ImageData.swapRB(data.rgba), data.width, data.height));
|
||||
Minecraft.getMinecraft().getTextureManager().loadTexture(ret.loc, ret.tex);
|
||||
spriteCache.put(i, ret);
|
||||
toFree.add(ret);
|
||||
aspectCB.accept((float)data.width / data.height);
|
||||
return ret.loc;
|
||||
}
|
||||
|
||||
private static ResourceLocation newLoc() {
|
||||
return new ResourceLocation("eagler:gui/server/custom_pause_menu/tex_" + textureId++);
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
icon_title_L = icon_title_R = null;
|
||||
icon_backToGame_L = icon_backToGame_R = null;
|
||||
icon_achievements_L = icon_achievements_R = null;
|
||||
icon_statistics_L = icon_statistics_R = null;
|
||||
icon_serverInfo_L = icon_serverInfo_R = null;
|
||||
icon_options_L = icon_options_R = null;
|
||||
icon_discord_L = icon_discord_R = null;
|
||||
icon_disconnect_L = icon_disconnect_R = null;
|
||||
icon_background_pause = icon_background_all = null;
|
||||
icon_watermark_pause = icon_watermark_all = null;
|
||||
icon_title_L_aspect = icon_title_R_aspect = 1.0f;
|
||||
icon_backToGame_L_aspect = icon_backToGame_R_aspect = 1.0f;
|
||||
icon_achievements_L_aspect = icon_achievements_R_aspect = 1.0f;
|
||||
icon_statistics_L_aspect = icon_statistics_R_aspect = 1.0f;
|
||||
icon_serverInfo_L_aspect = icon_serverInfo_R_aspect = 1.0f;
|
||||
icon_options_L_aspect = icon_options_R_aspect = 1.0f;
|
||||
icon_discord_L_aspect = icon_discord_R_aspect = 1.0f;
|
||||
icon_disconnect_L_aspect = icon_disconnect_R_aspect = 1.0f;
|
||||
icon_background_pause_aspect = icon_background_all_aspect = 1.0f;
|
||||
icon_watermark_pause_aspect = icon_watermark_all_aspect = 1.0f;
|
||||
serverInfoMode = 0;
|
||||
serverInfoEmbedPerms = SERVER_INFO_EMBED_PERMS_STRICT_CSP;
|
||||
serverInfoButtonText = null;
|
||||
serverInfoURL = null;
|
||||
serverInfoHash = null;
|
||||
serverInfoEmbedTitle = null;
|
||||
discordButtonMode = 0;
|
||||
discordButtonText = null;
|
||||
discordInviteURL = null;
|
||||
if(!toFree.isEmpty()) {
|
||||
TextureManager mgr = Minecraft.getMinecraft().getTextureManager();
|
||||
for(PauseMenuSprite rc : toFree) {
|
||||
mgr.deleteTexture(rc.loc);
|
||||
}
|
||||
toFree.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchControls;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
/**
|
||||
* Copyright (c) 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
|
||||
* 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 PointerInputAbstraction {
|
||||
|
||||
protected static Minecraft mc;
|
||||
protected static int oldMX = -1;
|
||||
protected static int oldMY = -1;
|
||||
protected static int oldTX = -1;
|
||||
protected static int oldTY = -1;
|
||||
protected static int dragStartX = -1;
|
||||
protected static int dragStartY = -1;
|
||||
protected static int dragStepStartX = -1;
|
||||
protected static int dragStepStartY = -1;
|
||||
protected static int dragUID = -1;
|
||||
|
||||
protected static int cursorX = -1;
|
||||
protected static int cursorY = -1;
|
||||
protected static int cursorDX = 0;
|
||||
protected static int cursorDY = 0;
|
||||
protected static boolean touchingScreen = false;
|
||||
protected static boolean touchingScreenNotButton = false;
|
||||
protected static boolean draggingNotTouching = false;
|
||||
protected static boolean touchMode = false;
|
||||
|
||||
public static void init(Minecraft mcIn) {
|
||||
mc = mcIn;
|
||||
oldMX = -1;
|
||||
oldMY = -1;
|
||||
oldTX = -1;
|
||||
oldTY = -1;
|
||||
dragStartX = -1;
|
||||
dragStartY = -1;
|
||||
dragStepStartX = -1;
|
||||
dragStepStartY = -1;
|
||||
dragUID = -1;
|
||||
cursorX = -1;
|
||||
cursorY = -1;
|
||||
cursorDX = 0;
|
||||
cursorDY = 0;
|
||||
touchingScreen = false;
|
||||
touchingScreenNotButton = false;
|
||||
draggingNotTouching = false;
|
||||
touchMode = !mcIn.mouseGrabSupported;
|
||||
}
|
||||
|
||||
public static void runGameLoop() {
|
||||
if(touchMode) {
|
||||
runTouchUpdate();
|
||||
}else {
|
||||
oldTX = -1;
|
||||
oldTY = -1;
|
||||
cursorX = oldMX = Mouse.getX();
|
||||
cursorY = oldMY = Mouse.getY();
|
||||
cursorDX += Mouse.getDX();
|
||||
cursorDY += Mouse.getDY();
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTouchUpdate() {
|
||||
int tc = Touch.touchPointCount();
|
||||
if (tc > 0) {
|
||||
TouchControls.update(true);
|
||||
touchingScreen = true;
|
||||
for(int i = 0; i < tc; ++i) {
|
||||
int uid = Touch.touchPointUID(i);
|
||||
if(TouchControls.touchControls.containsKey(uid)) {
|
||||
continue;
|
||||
}
|
||||
int tx = Touch.touchPointX(i);
|
||||
int ty = Touch.touchPointY(i);
|
||||
if(TouchControls.overlappingControl(tx, ty) != null) {
|
||||
continue;
|
||||
}
|
||||
if(mc.currentScreen == null && mc.ingameGUI.isTouchOverlapEagler(uid, tx, ty)) {
|
||||
continue;
|
||||
}
|
||||
cursorX = oldTX = tx;
|
||||
cursorY = oldTY = ty;
|
||||
oldMX = Mouse.getX();
|
||||
oldMY = Mouse.getY();
|
||||
touchingScreenNotButton = true;
|
||||
runTouchDeltaUpdate(uid);
|
||||
return;
|
||||
}
|
||||
touchingScreenNotButton = false;
|
||||
} else {
|
||||
TouchControls.update(false);
|
||||
touchingScreen = false;
|
||||
touchingScreenNotButton = false;
|
||||
dragStepStartX = -1;
|
||||
dragStepStartY = -1;
|
||||
dragStartX = -1;
|
||||
dragStartY = -1;
|
||||
dragUID = -1;
|
||||
final int tmp = Mouse.getX();
|
||||
final int tmp2 = Mouse.getY();
|
||||
if(oldTX == -1 || oldTY == -1) {
|
||||
cursorX = oldMX = tmp;
|
||||
cursorY = oldMY = tmp2;
|
||||
cursorDX += Mouse.getDX();
|
||||
cursorDY += Mouse.getDY();
|
||||
return;
|
||||
}
|
||||
if (oldMX == -1 || oldMY == -1) {
|
||||
oldMX = tmp;
|
||||
oldMY = tmp2;
|
||||
}
|
||||
if (oldMX == tmp && oldMY == tmp2) {
|
||||
cursorX = oldTX;
|
||||
cursorY = oldTY;
|
||||
}else {
|
||||
cursorX = oldMX = tmp;
|
||||
cursorY = oldMY = tmp2;
|
||||
cursorDX += Mouse.getDX();
|
||||
cursorDY += Mouse.getDY();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTouchDeltaUpdate(int uid) {
|
||||
if(uid != dragUID) {
|
||||
dragStartX = oldTX;
|
||||
dragStartY = oldTY;
|
||||
dragStepStartX = -1;
|
||||
dragStepStartY = -1;
|
||||
dragUID = uid;
|
||||
draggingNotTouching = false;
|
||||
return;
|
||||
}
|
||||
if(dragStepStartX != -1) {
|
||||
cursorDX += oldTX - dragStepStartX;
|
||||
}
|
||||
dragStepStartX = oldTX;
|
||||
if(dragStepStartY != -1) {
|
||||
cursorDY += oldTY - dragStepStartY;
|
||||
}
|
||||
dragStepStartY = oldTY;
|
||||
if(dragStartX != -1 && dragStartY != -1) {
|
||||
int dx = oldTX - dragStartX;
|
||||
int dy = oldTY - dragStartY;
|
||||
int len = dx * dx + dy * dy;
|
||||
int dm = Math.max((int)(6 * Display.getDPI()), 2);
|
||||
if(len > dm * dm) {
|
||||
draggingNotTouching = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTouchMode() {
|
||||
return touchMode;
|
||||
}
|
||||
|
||||
public static boolean isTouchingScreen() {
|
||||
return touchingScreen;
|
||||
}
|
||||
|
||||
public static boolean isTouchingScreenNotButton() {
|
||||
return touchingScreenNotButton;
|
||||
}
|
||||
|
||||
public static boolean isDraggingNotTouching() {
|
||||
return draggingNotTouching;
|
||||
}
|
||||
|
||||
public static void enterTouchModeHook() {
|
||||
if(!touchMode) {
|
||||
touchMode = true;
|
||||
if(mc.mouseGrabSupported) {
|
||||
mc.mouseHelper.ungrabMouseCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void enterMouseModeHook() {
|
||||
if(touchMode) {
|
||||
touchMode = false;
|
||||
touchingScreen = false;
|
||||
touchingScreenNotButton = false;
|
||||
if(mc.inGameHasFocus && mc.mouseGrabSupported) {
|
||||
mc.mouseHelper.grabMouseCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getVCursorX() {
|
||||
return cursorX;
|
||||
}
|
||||
|
||||
public static int getVCursorY() {
|
||||
return cursorY;
|
||||
}
|
||||
|
||||
public static int getVCursorDX() {
|
||||
int tmp = cursorDX;
|
||||
cursorDX = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public static int getVCursorDY() {
|
||||
int tmp = cursorDY;
|
||||
cursorDY = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public static boolean getVCursorButtonDown(int bt) {
|
||||
return (touchingScreenNotButton && bt == 0) || Mouse.isButtonDown(bt);
|
||||
}
|
||||
|
||||
}
|
134
sources/main/java/net/lax1dude/eaglercraft/v1_8/Touch.java
Normal file
134
sources/main/java/net/lax1dude/eaglercraft/v1_8/Touch.java
Normal file
@ -0,0 +1,134 @@
|
||||
package net.lax1dude.eaglercraft.v1_8;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
|
||||
|
||||
/**
|
||||
* 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 Touch {
|
||||
|
||||
public static boolean next() {
|
||||
return PlatformInput.touchNext();
|
||||
}
|
||||
|
||||
public static EnumTouchEvent getEventType() {
|
||||
return PlatformInput.touchGetEventType();
|
||||
}
|
||||
|
||||
public static int getEventTouchPointCount() {
|
||||
return PlatformInput.touchGetEventTouchPointCount();
|
||||
}
|
||||
|
||||
public static int getEventTouchX(int pointId) {
|
||||
return PlatformInput.touchGetEventTouchX(pointId);
|
||||
}
|
||||
|
||||
public static int getEventTouchY(int pointId) {
|
||||
return PlatformInput.touchGetEventTouchY(pointId);
|
||||
}
|
||||
|
||||
public static float getEventTouchRadiusX(int pointId) {
|
||||
return PlatformInput.touchGetEventTouchRadiusX(pointId);
|
||||
}
|
||||
|
||||
public static float getEventTouchRadiusY(int pointId) {
|
||||
return PlatformInput.touchGetEventTouchRadiusY(pointId);
|
||||
}
|
||||
|
||||
public static float getEventTouchRadiusMixed(int pointId) {
|
||||
return PlatformInput.touchGetEventTouchRadiusMixed(pointId);
|
||||
}
|
||||
|
||||
public static float getEventTouchForce(int pointId) {
|
||||
return PlatformInput.touchGetEventTouchForce(pointId);
|
||||
}
|
||||
|
||||
public static int getEventTouchPointUID(int pointId) {
|
||||
return PlatformInput.touchGetEventTouchPointUID(pointId);
|
||||
}
|
||||
|
||||
public static int touchPointCount() {
|
||||
return PlatformInput.touchPointCount();
|
||||
}
|
||||
|
||||
public static int touchPointX(int pointId) {
|
||||
return PlatformInput.touchPointX(pointId);
|
||||
}
|
||||
|
||||
public static int touchPointY(int pointId) {
|
||||
return PlatformInput.touchPointY(pointId);
|
||||
}
|
||||
|
||||
public static float touchPointRadiusX(int pointId) {
|
||||
return PlatformInput.touchRadiusX(pointId);
|
||||
}
|
||||
|
||||
public static float touchPointRadiusY(int pointId) {
|
||||
return PlatformInput.touchRadiusY(pointId);
|
||||
}
|
||||
|
||||
public static float touchPointRadiusMixed(int pointId) {
|
||||
return PlatformInput.touchRadiusMixed(pointId);
|
||||
}
|
||||
|
||||
public static float touchPointForce(int pointId) {
|
||||
return PlatformInput.touchForce(pointId);
|
||||
}
|
||||
|
||||
public static int touchPointUID(int pointId) {
|
||||
return PlatformInput.touchPointUID(pointId);
|
||||
}
|
||||
|
||||
public static void touchSetOpenKeyboardZone(int x, int y, int w, int h) {
|
||||
PlatformInput.touchSetOpenKeyboardZone(x, y, w, h);
|
||||
}
|
||||
|
||||
public static void closeDeviceKeyboard() {
|
||||
PlatformInput.touchCloseDeviceKeyboard();
|
||||
}
|
||||
|
||||
public static boolean isDeviceKeyboardOpenMAYBE() {
|
||||
return PlatformInput.touchIsDeviceKeyboardOpenMAYBE();
|
||||
}
|
||||
|
||||
public static String getPastedString() {
|
||||
return PlatformInput.touchGetPastedString();
|
||||
}
|
||||
|
||||
public static boolean checkPointTouching(int uid) {
|
||||
int cnt = PlatformInput.touchPointCount();
|
||||
if(cnt > 0) {
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
if(PlatformInput.touchPointUID(i) == uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int fetchPointIdx(int uid) {
|
||||
int cnt = PlatformInput.touchPointCount();
|
||||
if(cnt > 0) {
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
if(PlatformInput.touchPointUID(i) == uid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.boot_menu;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
/**
|
||||
* 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 GuiScreenEnterBootMenu extends GuiScreen {
|
||||
|
||||
private final GuiScreen parent;
|
||||
|
||||
public GuiScreenEnterBootMenu(GuiScreen parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
EagRuntime.setDisplayBootMenuNextRefresh(true);
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("gui.cancel")));
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
EagRuntime.setDisplayBootMenuNextRefresh(false);
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("enterBootMenu.title"), this.width / 2, 70, 11184810);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("enterBootMenu.text0"), this.width / 2, 90, 16777215);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
this.mc.displayGuiScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -25,7 +25,7 @@ public class EaglerLoadingCache<K, V> {
|
||||
|
||||
public EaglerLoadingCache(EaglerCacheProvider<K, V> provider) {
|
||||
this.provider = provider;
|
||||
this.cacheMap = new HashMap();
|
||||
this.cacheMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public V get(K key) {
|
||||
|
@ -0,0 +1,84 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.cookie;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore.ServerCookie;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
/**
|
||||
* 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 GuiScreenInspectSessionToken extends GuiScreen {
|
||||
|
||||
private final GuiScreen parent;
|
||||
private final ServerCookie cookie;
|
||||
|
||||
public GuiScreenInspectSessionToken(GuiScreenRevokeSessionToken parent, ServerCookie cookie) {
|
||||
this.parent = parent;
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 106, I18n.format("gui.done")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
String[][] toDraw = new String[][] {
|
||||
{
|
||||
I18n.format("inspectSessionToken.details.server"),
|
||||
I18n.format("inspectSessionToken.details.expires"),
|
||||
I18n.format("inspectSessionToken.details.length")
|
||||
},
|
||||
{
|
||||
cookie.server.length() > 32 ? cookie.server.substring(0, 30) + "..." : cookie.server,
|
||||
(new SimpleDateFormat("M/d/yyyy h:mm aa")).format(new Date(cookie.expires)),
|
||||
Integer.toString(cookie.cookie.length)
|
||||
}
|
||||
};
|
||||
int[] maxWidth = new int[2];
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
String[] strs = toDraw[i];
|
||||
int w = 0;
|
||||
for(int j = 0; j < strs.length; ++j) {
|
||||
int k = fontRendererObj.getStringWidth(strs[j]);
|
||||
if(k > w) {
|
||||
w = k;
|
||||
}
|
||||
}
|
||||
maxWidth[i] = w + 10;
|
||||
}
|
||||
int totalWidth = maxWidth[0] + maxWidth[1];
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("inspectSessionToken.title"), this.width / 2, 70, 16777215);
|
||||
this.drawString(fontRendererObj, toDraw[0][0], (this.width - totalWidth) / 2, 90, 11184810);
|
||||
this.drawString(fontRendererObj, toDraw[0][1], (this.width - totalWidth) / 2, 104, 11184810);
|
||||
this.drawString(fontRendererObj, toDraw[0][2], (this.width - totalWidth) / 2, 118, 11184810);
|
||||
this.drawString(fontRendererObj, toDraw[1][0], (this.width - totalWidth) / 2 + maxWidth[0], 90, 11184810);
|
||||
this.drawString(fontRendererObj, toDraw[1][1], (this.width - totalWidth) / 2 + maxWidth[0], 104, 11184810);
|
||||
this.drawString(fontRendererObj, toDraw[1][2], (this.width - totalWidth) / 2 + maxWidth[0], 118, 11184810);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
this.mc.displayGuiScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.cookie;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiSlot;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
/**
|
||||
* 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 GuiScreenRevokeSessionToken extends GuiScreen {
|
||||
protected GuiScreen parentScreen;
|
||||
private GuiScreenRevokeSessionToken.List list;
|
||||
private GuiButton inspectButton;
|
||||
private GuiButton revokeButton;
|
||||
|
||||
public GuiScreenRevokeSessionToken(GuiScreen parent) {
|
||||
this.parentScreen = parent;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(this.inspectButton = new GuiButton(10, this.width / 2 - 154, this.height - 38, 100, 20, I18n.format("revokeSessionToken.inspect")));
|
||||
this.buttonList.add(this.revokeButton = new GuiButton(9, this.width / 2 - 50, this.height - 38, 100, 20, I18n.format("revokeSessionToken.revoke")));
|
||||
this.buttonList.add(new GuiButton(6, this.width / 2 + 54, this.height - 38, 100, 20, I18n.format("gui.done")));
|
||||
this.list = new GuiScreenRevokeSessionToken.List(this.mc);
|
||||
this.list.registerScrollButtons(7, 8);
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
public void handleMouseInput() throws IOException {
|
||||
super.handleMouseInput();
|
||||
this.list.handleMouseInput();
|
||||
}
|
||||
|
||||
public void handleTouchInput() throws IOException {
|
||||
super.handleTouchInput();
|
||||
this.list.handleTouchInput();
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton parGuiButton) {
|
||||
if (parGuiButton.enabled) {
|
||||
switch (parGuiButton.id) {
|
||||
case 6:
|
||||
this.mc.displayGuiScreen(this.parentScreen);
|
||||
break;
|
||||
case 9:
|
||||
String s1 = list.getSelectedItem();
|
||||
if(s1 != null) {
|
||||
ServerCookieDataStore.ServerCookie cookie = ServerCookieDataStore.loadCookie(s1);
|
||||
if(cookie != null) {
|
||||
this.mc.displayGuiScreen(new GuiScreenSendRevokeRequest(this, cookie));
|
||||
}else {
|
||||
this.initGui();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
String s2 = list.getSelectedItem();
|
||||
if(s2 != null) {
|
||||
ServerCookieDataStore.ServerCookie cookie = ServerCookieDataStore.loadCookie(s2);
|
||||
if(cookie != null) {
|
||||
this.mc.displayGuiScreen(new GuiScreenInspectSessionToken(this, cookie));
|
||||
}else {
|
||||
this.initGui();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.list.actionPerformed(parGuiButton);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateButtons() {
|
||||
inspectButton.enabled = revokeButton.enabled = list.getSelectedItem() != null;
|
||||
}
|
||||
|
||||
public void drawScreen(int i, int j, float f) {
|
||||
this.list.drawScreen(i, j, f);
|
||||
this.drawCenteredString(this.fontRendererObj, I18n.format("revokeSessionToken.title"), this.width / 2, 16, 16777215);
|
||||
this.drawCenteredString(this.fontRendererObj, I18n.format("revokeSessionToken.note.0"), this.width / 2, this.height - 66, 8421504);
|
||||
this.drawCenteredString(this.fontRendererObj, I18n.format("revokeSessionToken.note.1"), this.width / 2, this.height - 56, 8421504);
|
||||
super.drawScreen(i, j, f);
|
||||
}
|
||||
|
||||
class List extends GuiSlot {
|
||||
private final java.util.List<String> cookieNames = Lists.newArrayList();
|
||||
|
||||
public List(Minecraft mcIn) {
|
||||
super(mcIn, GuiScreenRevokeSessionToken.this.width, GuiScreenRevokeSessionToken.this.height, 32, GuiScreenRevokeSessionToken.this.height - 75 + 4, 18);
|
||||
ServerCookieDataStore.flush();
|
||||
cookieNames.addAll(ServerCookieDataStore.getRevokableServers());
|
||||
Collections.sort(cookieNames);
|
||||
}
|
||||
|
||||
protected int getSize() {
|
||||
return this.cookieNames.size();
|
||||
}
|
||||
|
||||
protected void elementClicked(int i, boolean var2, int var3, int var4) {
|
||||
selectedElement = i;
|
||||
GuiScreenRevokeSessionToken.this.updateButtons();
|
||||
}
|
||||
|
||||
protected boolean isSelected(int i) {
|
||||
return selectedElement == i;
|
||||
}
|
||||
|
||||
protected String getSelectedItem() {
|
||||
return selectedElement == -1 ? null : cookieNames.get(selectedElement);
|
||||
}
|
||||
|
||||
protected int getContentHeight() {
|
||||
return this.getSize() * 18;
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
GuiScreenRevokeSessionToken.this.drawDefaultBackground();
|
||||
}
|
||||
|
||||
protected void drawSlot(int i, int var2, int j, int var4, int var5, int var6) {
|
||||
GuiScreenRevokeSessionToken.this.drawCenteredString(GuiScreenRevokeSessionToken.this.fontRendererObj,
|
||||
this.cookieNames.get(i), this.width / 2, j + 1, 16777215);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.cookie;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore.ServerCookie;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.QueryResponse;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.ServerQueryDispatch;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
/**
|
||||
* 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 GuiScreenSendRevokeRequest extends GuiScreen {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("SessionRevokeRequest");
|
||||
|
||||
private GuiScreen parent;
|
||||
private ServerCookie cookie;
|
||||
private String title;
|
||||
private String message;
|
||||
private int timer = 0;
|
||||
private boolean cancelRequested = false;
|
||||
private IServerQuery query = null;
|
||||
private boolean hasSentPacket = false;
|
||||
|
||||
public GuiScreenSendRevokeRequest(GuiScreen parent, ServerCookie cookie) {
|
||||
this.parent = parent;
|
||||
this.cookie = cookie;
|
||||
this.title = I18n.format("revokeSendingScreen.title");
|
||||
this.message = I18n.format("revokeSendingScreen.message.opening", cookie.server);
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("gui.cancel")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(fontRendererObj, title, this.width / 2, 70, 11184810);
|
||||
this.drawCenteredString(fontRendererObj, message, this.width / 2, 90, 16777215);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
++timer;
|
||||
if (timer > 1) {
|
||||
if(query == null) {
|
||||
logger.info("Attempting to revoke session tokens for: {}", cookie.server);
|
||||
query = ServerQueryDispatch.sendServerQuery(cookie.server, "revoke_session_token");
|
||||
if(query == null) {
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.connectionError", parent));
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
query.update();
|
||||
QueryResponse resp = query.getResponse();
|
||||
if(resp != null) {
|
||||
if(resp.responseType.equalsIgnoreCase("revoke_session_token") && (hasSentPacket ? resp.isResponseJSON() : resp.isResponseString())) {
|
||||
if(!hasSentPacket) {
|
||||
String str = resp.getResponseString();
|
||||
if("ready".equalsIgnoreCase(str)) {
|
||||
hasSentPacket = true;
|
||||
message = I18n.format("revokeSendingScreen.message.sending");
|
||||
query.send(cookie.cookie);
|
||||
return;
|
||||
}else {
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
JSONObject json = resp.getResponseJSON();
|
||||
String stat = json.optString("status");
|
||||
if("ok".equalsIgnoreCase(stat)) {
|
||||
if(hasSentPacket) {
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeSuccess.title", "revokeSuccess.desc", parent));
|
||||
ServerCookieDataStore.clearCookie(cookie.server);
|
||||
return;
|
||||
}else {
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
|
||||
return;
|
||||
}
|
||||
}else if("error".equalsIgnoreCase(stat)) {
|
||||
int code = json.optInt("code", -1);
|
||||
if(code == -1) {
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
|
||||
return;
|
||||
}else {
|
||||
String key;
|
||||
switch(code) {
|
||||
case 1:
|
||||
key = "revokeFailure.desc.notSupported";
|
||||
break;
|
||||
case 2:
|
||||
key = "revokeFailure.desc.notAllowed";
|
||||
break;
|
||||
case 3:
|
||||
key = "revokeFailure.desc.notFound";
|
||||
break;
|
||||
case 4:
|
||||
key = "revokeFailure.desc.serverError";
|
||||
break;
|
||||
default:
|
||||
key = "revokeFailure.desc.genericCode";
|
||||
break;
|
||||
}
|
||||
logger.error("Recieved error code {}! ({})", code, key);
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", key, parent));
|
||||
if(json.optBoolean("delete", false)) {
|
||||
ServerCookieDataStore.clearCookie(cookie.server);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
logger.error("Recieved unknown status \"{}\"!", stat);
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(query.isClosed()) {
|
||||
if(!hasSentPacket || query.responsesAvailable() == 0) {
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.connectionError", parent));
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
if(timer > 400) {
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.connectionError", parent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(cancelRequested) {
|
||||
query.close();
|
||||
this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.cancelled", parent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
cancelRequested = true;
|
||||
par1GuiButton.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,294 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.cookie;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IFramebufferGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformAssets;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.DrawUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GLSLHeader;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.VSHInputLayoutParser;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
|
||||
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
|
||||
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
|
||||
import static net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.ExtGLEnums.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Base64;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.GeneralDigest;
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.SHA256Digest;
|
||||
|
||||
/**
|
||||
* 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 HardwareFingerprint {
|
||||
|
||||
// This is used for generating encryption keys for storing cookies,
|
||||
// its supposed to make session hijacking more difficult for skids
|
||||
|
||||
private static final String fingerprintIMG = "/9j/4AAQSkZJRgABAQEBLAEsAAD//gAKZnVjayBvZmb/4gKwSUNDX1BST0ZJTEUAAQEAAAKgbGNtcwRAAABtbnRyUkdCIFhZWiAH6AAGABAAAgArACNhY3NwTVNGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1kZXNjAAABIAAAAEBjcHJ0AAABYAAAADZ3dHB0AAABmAAAABRjaGFkAAABrAAAACxyWFlaAAAB2AAAABRiWFlaAAAB7AAAABRnWFlaAAACAAAAABRyVFJDAAACFAAAACBnVFJDAAACFAAAACBiVFJDAAACFAAAACBjaHJtAAACNAAAACRkbW5kAAACWAAAACRkbWRkAAACfAAAACRtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACQAAAAcAEcASQBNAFAAIABiAHUAaQBsAHQALQBpAG4AIABzAFIARwBCbWx1YwAAAAAAAAABAAAADGVuVVMAAAAaAAAAHABQAHUAYgBsAGkAYwAgAEQAbwBtAGEAaQBuAABYWVogAAAAAAAA9tYAAQAAAADTLXNmMzIAAAAAAAEMQgAABd7///MlAAAHkwAA/ZD///uh///9ogAAA9wAAMBuWFlaIAAAAAAAAG+gAAA49QAAA5BYWVogAAAAAAAAJJ8AAA+EAAC2xFhZWiAAAAAAAABilwAAt4cAABjZcGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACltjaHJtAAAAAAADAAAAAKPXAABUfAAATM0AAJmaAAAmZwAAD1xtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAEcASQBNAFBtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEL/2wBDAAoHBwkHBgoJCAkLCwoMDxkQDw4ODx4WFxIZJCAmJSMgIyIoLTkwKCo2KyIjMkQyNjs9QEBAJjBGS0U+Sjk/QD3/2wBDAQsLCw8NDx0QEB09KSMpPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT3/wgARCACAAIADAREAAhEBAxEB/8QAGwAAAgMBAQEAAAAAAAAAAAAAAQIABAUDBgf/xAAYAQEBAQEBAAAAAAAAAAAAAAAAAQIDBP/aAAwDAQACEAMQAAABx95IwaIRghDRCFCElZ+KQhpghGDRCFCQNEzsUjUQjBDRChCENQJn4pDXfNuSvBBUJYK52Q5ahIZ+KSxLtc9jAcbO8OpA0YENodZpdJWszsUm1z3alHnuBZurO+SA5+PVPTQ7zv0zd1MLpnGzSem49OQIPMeslCpA82ueVj05fcuWdtPCBPW8elGzlRIMFCElOPZoJe0+dx2PR8+mdYoSAFQgFHq3ZsWWa+fxZ01+O6lKgqiWhxRhBQpv6mlXgdS1Loct8kAtcjiWBRxQANHWd+vEw5M67HQghXGO4AEFLms+hrxFhrW49KliDhGAABAALes79eI1CbnHpVshzAQhCEIAmpa3nJCbPHpwsgBRBQBGICrlzd1PN1DW5bSBSgAcxElOpQLo3OtX/8QAJxAAAQQBBAEEAgMAAAAAAAAAAQACAxEQBBITICEUIjAxMkEjNFD/2gAIAQEAAQUC/wBNkZevThcDVwtXC1cAXAuAoxOCMbh2iZyPqsX8HG16lhMXTSMqHAZP6jpI/Y2DVcxCCYA9s8JgfiBtaUq+zm7hHAyLATFqo+TTIeSRUbirVq1uW5bluW4K0FCE/wAilCLmkcirV4tWrVq0HprlD9Y039iQ9JXmMtO5qLqV+MbqWmfuZ+gC4we3UPPnL27mxGkTQaOhWjdhp2Na7cre0h99HsTQT20n5JxtzPzkHksX0rV/BpT7gQcyYpEZvtHbjE8x5PlmT8ELP4ItOGuw3zD3vo32r9f/xAAeEQACAQUAAwAAAAAAAAAAAAAAEQEQIDAxUAIhQP/aAAgBAwEBPwHpoQhCEIQr4qsvjSD2TbEk3Rqr5kb+CN59D7s2RrN//8QAIhEAAQMEAgIDAAAAAAAAAAAAAQACEhARIDEDMBNAIUFQ/9oACAECAQE/Af0ybKSkVIqRU1NSUgrjIm1HuiF5SmulgSAg4UBQN8H050XMiuHA3c5P44fK4zcVBvU7o5odteFqAtg5hBuEZu2mNtUejdfXeAna9B2u/ZRHeEfe33jA77BT/8QAJxAAAQIFAwMFAQAAAAAAAAAAAQARAhAhMDEgQVESImEDUGJxgZH/2gAIAQEABj8C9zosme6yVlUMsamVLVQnzDzoMXNh0zVn0xYKY42M4R+2GK7RoPIrMC6RKD7uvOHTRPZYVUL6umTnW+5TbrurpcZVbHhQ/d6hvngByuuEvyJwnxcPzib8CJNZw3PRg4gf+y//xAAkEAEAAgIBBAIDAQEAAAAAAAABABEQITFBUWFxIIGR8PFQsf/aAAgBAQABPyH/AE39Nd4GbulPd+54X8z9jhK/zHpMWqj8wa1/Xyrenl9QAoUGKcXgwMuFQdx/6oldyOPg7hqsdI6zYXz0qBrFwl/2wF1CXvFKdw5bLfcMh3g29ywwt8SBWWRJaV6wnKc4WhppgIBy6nZwoJ054y0vnrKnqeSB7xXNhc9kKwrXjOMOkdOJK/AKwo5htQdfcXWNvbK1juVGBXYldhV7sLWYuBPTEDZLisKuxC0CfyWOOGAgysrkwFkGMqaGo2zzBjudcb4i71HwzXfZBgRiblS/toGM8GGMeJo64uE47XQR03hBILpNyObZvHXHSAXdENsE8YJu33jKM7M4l4Dg64eIABpTeIibDl65XlB8BcSoy5cOMM3bz+49wcAJq8v6VfJNx1OEvC6uauwL3tBj/9oADAMBAAIAAwAAABD9mRbSTt1t0bIAF+n8iJQX9mluqdyUVE09DAPykEK/iOdbRe8nvNsaLtpZ+CB9RFxmQADt+ChzpmW03P7QNkikzbp/AkyUoZrmRKm2JYrYU5LbJaLJU0pbLQ1Z+klOwjL/xAAeEQEAAgIDAQEBAAAAAAAAAAABABEQICEwMUFAUP/aAAgBAwEBPxD+mJlZWUlZXPaI7C3AXglaVKwhErQcXHALa/CWQVGMSsioYcS2oiQo8i3HDip81qVq5qHpHuWsT1unGHsceIW4ZyS+twtw9jK63R7GeZ+fsDj/xAAfEQEAAgIDAAMBAAAAAAAAAAABABEQISAwMUFQYXH/2gAIAQIBAT8Q+zGL8IrT+IHANyqXP2DYwu8hizh6kW6cKQOBbrC2QNYWr+Mvk1UTQxTWEGpQy7UGAVGyAKOPcKEUahh04uevG+gwW1DlXIxbNHDrIYsJs4dhipUlkoZXWYFE8MJeK6TgdhtqX4cul7PdxbyaXZ4x/8QAJRABAAICAgEEAwADAAAAAAAAAQARITFBUWEQcZGhgbHhwdHw/9oACAEBAAE/EBhCDCEGEGXBhCD6DCEIMIQYQYMGDBhB9CEGDCEGEIMIMNQYegwYTVAtL0TKZ4UEAFjdsNePmS1wj2jHgfiL6Z72lLL9xIJSLqhLcAc5fqG4MuDBiZquXoQIDCA4lXuZ8F9S/iZGJdSw8QggXzHMFjupfG/2OA2aA56fMIMJcZp3wf1+oMd63WI/LNqeSMC9yq1vqaTBxMWXS4ykS/CRRTcE4ekf3GNn/BHMGDmcKrS7yiomtzOywRtvMuubjKtmDTGl52MIthPKAjqXYTiPbtv22fEGZmkB7sxbQUuaKqADe03UvVR52BbYQGDFJOU325g2S35jtRa8wEObK4akp9T3RcfVj+G4QKyH0TwImLaIPZEBLwSagO5YbMQnnXmOKy4WW2ntLn+4sOXwn6ZgTlgVmYxYTuWbLuCByahNMWaIhBT1Oj5i5xfvASx7Z+p0AGTmFsIASbaLfMOXbcJXKHuVcWYsxgBXiFgqY8kuWM0suh49AhbwQiUp8wirdaTATjBHIf1CRqVeuf8AD5Jhihwm2wzQsuHUULmLm10cxwUDiWBGZUdzpxD2g2zyRYDxCZNGOo4gMaE+4pKuLVFMBpzoBddwA5izZ+osHLwRzzFqEIllOf8AcpK2Mrr0VI9MVANBlvzEGSUt6QOUF36AT00Udeg/S3jQx9qH5isgUZobxwlkCVPJi+o4bdR+pcCEhdwgdRYnprC1givIW1+R8So0Sq6vcCVL/wAi+DUo5ihYkuLWiOSkjcMSyxC0AlodEEfALlhHUubF/STqcT//2Q==";
|
||||
|
||||
private static final String shaderPrecision = "precision lowp int;\nprecision mediump float;\nprecision mediump sampler2D;\n";
|
||||
|
||||
private static byte[] fingerprint = null;
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("HardwareFingerprint");
|
||||
|
||||
public static byte[] getFingerprint() {
|
||||
if(fingerprint == null) {
|
||||
try {
|
||||
fingerprint = generateFingerprint();
|
||||
}catch(Throwable t) {
|
||||
fingerprint = new byte[0];
|
||||
}
|
||||
if(fingerprint.length == 0) {
|
||||
logger.error("Failed to calculate hardware fingerprint, server cookies will not be encrypted!");
|
||||
}
|
||||
}
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
private static byte[] generateFingerprint() {
|
||||
ImageData img = PlatformAssets.loadImageFile(Base64.decodeBase64(fingerprintIMG), "image/jpeg");
|
||||
if(img == null) {
|
||||
logger.error("Input image data is corrupt!");
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
int[][] mipmapLevels = TextureUtil.generateMipmapData(7, 128,
|
||||
new int[][] { img.pixels, null, null, null, null, null, null, null });
|
||||
|
||||
int helperTexture = GlStateManager.generateTexture();
|
||||
GlStateManager.bindTexture(helperTexture);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
TextureUtil.allocateTextureImpl(helperTexture, 7, 128, 128);
|
||||
TextureUtil.uploadTextureMipmap(mipmapLevels, 128, 128, 0, 0, false, false);
|
||||
if(checkAnisotropicFilteringSupport()) {
|
||||
_wglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 16.0f);
|
||||
}
|
||||
|
||||
IShaderGL vert;
|
||||
List<VSHInputLayoutParser.ShaderInput> vertLayout;
|
||||
if(DrawUtils.vshLocal != null) {
|
||||
vert = DrawUtils.vshLocal;
|
||||
vertLayout = DrawUtils.vshLocalLayout;
|
||||
}else {
|
||||
String vshLocalSrc = EagRuntime.getRequiredResourceString("/assets/eagler/glsl/local.vsh");
|
||||
vertLayout = VSHInputLayoutParser.getShaderInputs(vshLocalSrc);
|
||||
vert = _wglCreateShader(GL_VERTEX_SHADER);
|
||||
_wglShaderSource(vert, GLSLHeader.getVertexHeaderCompat(vshLocalSrc, DrawUtils.vertexShaderPrecision));
|
||||
_wglCompileShader(vert);
|
||||
if(_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) {
|
||||
_wglDeleteShader(vert);
|
||||
GlStateManager.deleteTexture(helperTexture);
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(EagRuntime.getRequiredResourceString("/assets/eagler/glsl/hw_fingerprint.fsh"), shaderPrecision));
|
||||
_wglCompileShader(frag);
|
||||
if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
|
||||
_wglDeleteShader(vert);
|
||||
_wglDeleteShader(frag);
|
||||
GlStateManager.deleteTexture(helperTexture);
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
IProgramGL program = _wglCreateProgram();
|
||||
|
||||
_wglAttachShader(program, vert);
|
||||
_wglAttachShader(program, frag);
|
||||
|
||||
if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
|
||||
VSHInputLayoutParser.applyLayout(program, vertLayout);
|
||||
}
|
||||
|
||||
_wglLinkProgram(program);
|
||||
_wglDetachShader(program, vert);
|
||||
_wglDetachShader(program, frag);
|
||||
if(DrawUtils.vshLocal == null) {
|
||||
_wglDeleteShader(vert);
|
||||
}
|
||||
_wglDeleteShader(frag);
|
||||
|
||||
if(_wglGetProgrami(program, GL_LINK_STATUS) != GL_TRUE) {
|
||||
_wglDeleteProgram(program);
|
||||
GlStateManager.deleteTexture(helperTexture);
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
EaglercraftGPU.bindGLShaderProgram(program);
|
||||
_wglUniform1i(_wglGetUniformLocation(program, "u_inputTexture"), 0);
|
||||
|
||||
float fovy = 90.0f;
|
||||
float aspect = 1.0f;
|
||||
float zNear = 0.01f;
|
||||
float zFar = 100.0f;
|
||||
FloatBuffer matrixUploadBuffer = EagRuntime.allocateFloatBuffer(16);
|
||||
float toRad = 0.0174532925f;
|
||||
float cotangent = (float) Math.cos(fovy * toRad * 0.5f) / (float) Math.sin(fovy * toRad * 0.5f);
|
||||
|
||||
matrixUploadBuffer.put(cotangent / aspect);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(cotangent);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put((zFar + zNear) / (zFar - zNear));
|
||||
matrixUploadBuffer.put(2.0f * zFar * zNear / (zFar - zNear));
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
matrixUploadBuffer.put(-1.0f);
|
||||
matrixUploadBuffer.put(0.0f);
|
||||
|
||||
matrixUploadBuffer.flip();
|
||||
_wglUniformMatrix4fv(_wglGetUniformLocation(program, "u_textureMatrix"), false, matrixUploadBuffer);
|
||||
EagRuntime.freeFloatBuffer(matrixUploadBuffer);
|
||||
|
||||
int[] oldViewport = new int[4];
|
||||
EaglercraftGPU.glGetInteger(GL_VIEWPORT, oldViewport);
|
||||
IFramebufferGL framebuffer = _wglCreateFramebuffer();
|
||||
int renderTexture = GlStateManager.generateTexture();
|
||||
GlStateManager.bindTexture(renderTexture);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
int dataLength;
|
||||
int type;
|
||||
if(EaglercraftGPU.checkHDRFramebufferSupport(32)) {
|
||||
dataLength = 256 * 256 * 4 * 4;
|
||||
type = GL_FLOAT;
|
||||
EaglercraftGPU.createFramebufferHDR32FTexture(GL_TEXTURE_2D, 0, 256, 256, GL_RGBA, false);
|
||||
}else if(EaglercraftGPU.checkHDRFramebufferSupport(16)) {
|
||||
dataLength = 256 * 256 * 4 * 2;
|
||||
type = _GL_HALF_FLOAT;
|
||||
EaglercraftGPU.createFramebufferHDR16FTexture(GL_TEXTURE_2D, 0, 256, 256, GL_RGBA, false);
|
||||
}else {
|
||||
dataLength = 256 * 256 * 4;
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
EaglercraftGPU.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
|
||||
}
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer);
|
||||
_wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EaglercraftGPU.getNativeTexture(renderTexture), 0);
|
||||
_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
|
||||
|
||||
GlStateManager.viewport(0, 0, 256, 256);
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.bindTexture(helperTexture);
|
||||
|
||||
DrawUtils.drawStandardQuad2D();
|
||||
|
||||
_wglDeleteProgram(program);
|
||||
GlStateManager.deleteTexture(helperTexture);
|
||||
|
||||
ByteBuffer readBuffer = EagRuntime.allocateByteBuffer(dataLength);
|
||||
EaglercraftGPU.glReadPixels(0, 0, 256, 256, GL_RGBA, type, readBuffer);
|
||||
|
||||
_wglBindFramebuffer(_GL_FRAMEBUFFER, null);
|
||||
_wglDeleteFramebuffer(framebuffer);
|
||||
GlStateManager.deleteTexture(renderTexture);
|
||||
GlStateManager.viewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
|
||||
|
||||
SHA256Digest digest = new SHA256Digest();
|
||||
byte[] copyBuffer = new byte[1024];
|
||||
|
||||
byte[] b = ("eag" + EaglercraftGPU.glGetString(GL_VENDOR) + "; eag " + EaglercraftGPU.glGetString(GL_RENDERER)).getBytes(StandardCharsets.UTF_8);
|
||||
digest.update(b, 0, b.length);
|
||||
|
||||
digestInts(digest, _wglGetInteger(0x8869), _wglGetInteger(0x8DFB), _wglGetInteger(0x8B4C), _wglGetInteger(0x8DFC), copyBuffer);
|
||||
digestInts(digest, _wglGetInteger(0x8DFD), _wglGetInteger(0x8872), _wglGetInteger(0x84E8), 69, copyBuffer);
|
||||
digestInts(digest, _wglGetInteger(0x0D33), _wglGetInteger(0x851C), _wglGetInteger(0x8B4D), 69, copyBuffer);
|
||||
|
||||
if(EaglercraftGPU.checkOpenGLESVersion() >= 300) {
|
||||
digestInts(digest, _wglGetInteger(0x8B4A), _wglGetInteger(0x8A2B), _wglGetInteger(0x9122), _wglGetInteger(0x8B4B), copyBuffer);
|
||||
digestInts(digest, _wglGetInteger(0x8C8A), _wglGetInteger(0x8C8B), _wglGetInteger(0x8C80), _wglGetInteger(0x8B49), copyBuffer);
|
||||
digestInts(digest, _wglGetInteger(0x8A2D), _wglGetInteger(0x9125), _wglGetInteger(0x8904), _wglGetInteger(0x8905), copyBuffer);
|
||||
digestInts(digest, _wglGetInteger(0x8824), _wglGetInteger(0x8073), _wglGetInteger(0x88FF), _wglGetInteger(0x84FD), copyBuffer);
|
||||
digestInts(digest, _wglGetInteger(0x8CDF), _wglGetInteger(0x8A2F), _wglGetInteger(0x8A30), _wglGetInteger(0x8A34), copyBuffer);
|
||||
digestInts(digest, _wglGetInteger(0x8A2E), _wglGetInteger(0x8A31), _wglGetInteger(0x8A33), _wglGetInteger(0x8D57), copyBuffer);
|
||||
}
|
||||
|
||||
try {
|
||||
List<String> exts = Lists.newArrayList(getAllExtensions());
|
||||
Collections.sort(exts);
|
||||
EaglercraftRandom rand = new EaglercraftRandom(6942069420l + exts.size() * 69l + b.length);
|
||||
for (int i = exts.size() - 1; i > 0; --i) {
|
||||
int j = rand.nextInt(i + 1);
|
||||
Collections.swap(exts, i, j);
|
||||
}
|
||||
b = String.join(":>", exts).getBytes(StandardCharsets.UTF_8);
|
||||
digest.update(b, 0, b.length);
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
|
||||
int i;
|
||||
while(readBuffer.hasRemaining()) {
|
||||
i = Math.min(readBuffer.remaining(), copyBuffer.length);
|
||||
readBuffer.get(copyBuffer, 0, i);
|
||||
digest.update(copyBuffer, 0, i);
|
||||
}
|
||||
|
||||
EagRuntime.freeByteBuffer(readBuffer);
|
||||
|
||||
byte[] hashOut = new byte[32];
|
||||
digest.doFinal(hashOut, 0);
|
||||
|
||||
return hashOut;
|
||||
}
|
||||
|
||||
private static void digestInts(GeneralDigest digest, int i1, int i2, int i3, int i4, byte[] tmpBuffer) {
|
||||
tmpBuffer[0] = (byte)(i1 >>> 24);
|
||||
tmpBuffer[1] = (byte)(i1 >>> 16);
|
||||
tmpBuffer[2] = (byte)(i1 >>> 8);
|
||||
tmpBuffer[3] = (byte)(i1 & 0xFF);
|
||||
tmpBuffer[4] = (byte)(i2 >>> 24);
|
||||
tmpBuffer[5] = (byte)(i2 >>> 16);
|
||||
tmpBuffer[6] = (byte)(i2 >>> 8);
|
||||
tmpBuffer[7] = (byte)(i2 & 0xFF);
|
||||
tmpBuffer[8] = (byte)(i3 >>> 24);
|
||||
tmpBuffer[9] = (byte)(i3 >>> 16);
|
||||
tmpBuffer[10] = (byte)(i3 >>> 8);
|
||||
tmpBuffer[11] = (byte)(i3 & 0xFF);
|
||||
tmpBuffer[12] = (byte)(i4 >>> 24);
|
||||
tmpBuffer[13] = (byte)(i4 >>> 16);
|
||||
tmpBuffer[14] = (byte)(i4 >>> 8);
|
||||
tmpBuffer[15] = (byte)(i4 & 0xFF);
|
||||
digest.update(tmpBuffer, 0, 16);
|
||||
}
|
||||
}
|
@ -0,0 +1,396 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.cookie;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.AESLightEngine;
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
|
||||
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 ServerCookieDataStore {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("ServerCookieDataStore");
|
||||
|
||||
private static final Map<String,ServerCookie> dataStore = new HashMap<>();
|
||||
|
||||
public static final String localStorageKey = "c";
|
||||
|
||||
public static class ServerCookie {
|
||||
|
||||
public final String server;
|
||||
public final byte[] cookie;
|
||||
public final long expires;
|
||||
public final boolean revokeQuerySupported;
|
||||
public final boolean saveCookieToDisk;
|
||||
|
||||
public ServerCookie(String server, byte[] cookie, long expires, boolean revokeQuerySupported, boolean saveCookieToDisk) {
|
||||
this.server = server;
|
||||
this.cookie = cookie;
|
||||
this.expires = expires;
|
||||
this.revokeQuerySupported = revokeQuerySupported;
|
||||
this.saveCookieToDisk = saveCookieToDisk;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
if(EagRuntime.getConfiguration().isEnableServerCookies()) {
|
||||
loadData(HardwareFingerprint.getFingerprint());
|
||||
}
|
||||
}
|
||||
|
||||
public static ServerCookie loadCookie(String server) {
|
||||
if(!EagRuntime.getConfiguration().isEnableServerCookies()) {
|
||||
return null;
|
||||
}
|
||||
server = normalize(server);
|
||||
ServerCookie cookie = dataStore.get(server);
|
||||
if(cookie == null) {
|
||||
return null;
|
||||
}
|
||||
long timestamp = System.currentTimeMillis();
|
||||
if(timestamp > cookie.expires) {
|
||||
dataStore.remove(server);
|
||||
saveData(HardwareFingerprint.getFingerprint());
|
||||
return null;
|
||||
}
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public static void saveCookie(String server, long expires, byte[] data, boolean revokeQuerySupported, boolean saveCookieToDisk) {
|
||||
if(!EagRuntime.getConfiguration().isEnableServerCookies()) {
|
||||
return;
|
||||
}
|
||||
server = normalize(server);
|
||||
if(expires > 604800l) {
|
||||
clearCookie(server);
|
||||
logger.error("Server \"{}\" tried to set a cookie for {} days! (The max is 7 days)", server, (expires / 604800l));
|
||||
return;
|
||||
}
|
||||
if(data.length > 255) {
|
||||
clearCookie(server);
|
||||
logger.error("Server \"{}\" tried to set a {} byte cookie! (The max length is 255 bytes)", server, data.length);
|
||||
return;
|
||||
}
|
||||
if(expires < 0l || data.length == 0) {
|
||||
clearCookie(server);
|
||||
return;
|
||||
}
|
||||
long expiresRelative = System.currentTimeMillis() + expires * 1000l;
|
||||
dataStore.put(server, new ServerCookie(server, data, expiresRelative, revokeQuerySupported, saveCookieToDisk));
|
||||
saveData(HardwareFingerprint.getFingerprint());
|
||||
}
|
||||
|
||||
public static void clearCookie(String server) {
|
||||
if(!EagRuntime.getConfiguration().isEnableServerCookies()) {
|
||||
return;
|
||||
}
|
||||
if(dataStore.remove(normalize(server)) != null) {
|
||||
saveData(HardwareFingerprint.getFingerprint());
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearCookiesLow() {
|
||||
dataStore.clear();
|
||||
}
|
||||
|
||||
private static String normalize(String server) {
|
||||
int j = server.indexOf('/');
|
||||
if(j != -1) {
|
||||
int i = server.indexOf("://");
|
||||
if(i != -1) {
|
||||
j = server.indexOf('/', i + 3);
|
||||
if(j == -1) {
|
||||
return server.toLowerCase();
|
||||
}else {
|
||||
return server.substring(0, j).toLowerCase() + server.substring(j);
|
||||
}
|
||||
}else {
|
||||
return server.substring(0, j).toLowerCase() + server.substring(j);
|
||||
}
|
||||
}else {
|
||||
return server.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getAllServers() {
|
||||
return dataStore.keySet();
|
||||
}
|
||||
|
||||
public static List<String> getRevokableServers() {
|
||||
List<String> ret = new ArrayList<>(dataStore.size());
|
||||
for(ServerCookie c : dataStore.values()) {
|
||||
if(c.revokeQuerySupported) {
|
||||
ret.add(c.server);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int size() {
|
||||
return dataStore.size();
|
||||
}
|
||||
|
||||
public static int numRevokable() {
|
||||
int i = 0;
|
||||
for(ServerCookie c : dataStore.values()) {
|
||||
if(c.revokeQuerySupported) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public static void flush() {
|
||||
Iterator<ServerCookie> itr = dataStore.values().iterator();
|
||||
boolean changed = false;
|
||||
while(itr.hasNext()) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
ServerCookie cookie = itr.next();
|
||||
if(timestamp > cookie.expires) {
|
||||
itr.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(changed) {
|
||||
saveData(HardwareFingerprint.getFingerprint());
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadData(byte[] key) {
|
||||
dataStore.clear();
|
||||
byte[] cookiesTag = PlatformApplication.getLocalStorage(localStorageKey, false);
|
||||
if(cookiesTag == null) {
|
||||
return;
|
||||
}
|
||||
if(cookiesTag.length <= 25) {
|
||||
PlatformApplication.setLocalStorage(localStorageKey, null, false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
byte[] decrypted;
|
||||
int decryptedLen;
|
||||
switch(cookiesTag[0]) {
|
||||
case 2:
|
||||
if(key == null || key.length == 0) {
|
||||
throw new IOException("Data is encrypted!");
|
||||
}
|
||||
decrypted = new byte[cookiesTag.length - 5];
|
||||
decryptedLen = (cookiesTag[1] << 24) | (cookiesTag[2] << 16) | (cookiesTag[3] << 8) | (cookiesTag[4] & 0xFF);
|
||||
if(decryptedLen < 25) {
|
||||
throw new IOException("too short!");
|
||||
}
|
||||
AESLightEngine aes = new AESLightEngine();
|
||||
aes.init(false, key);
|
||||
int bs = aes.getBlockSize();
|
||||
if(decrypted.length % bs != 0) {
|
||||
throw new IOException("length not aligned to block size!");
|
||||
}
|
||||
byte[] cbcHelper = new byte[] { (byte) 29, (byte) 163, (byte) 4, (byte) 20, (byte) 207, (byte) 26,
|
||||
(byte) 140, (byte) 55, (byte) 246, (byte) 250, (byte) 141, (byte) 183, (byte) 153, (byte) 154,
|
||||
(byte) 59, (byte) 4 };
|
||||
for(int i = 0; i < decryptedLen; i += bs) {
|
||||
processBlockDecryptHelper(aes, cookiesTag, 5 + i, decrypted, i, bs, Math.min(decryptedLen - i, bs), cbcHelper);
|
||||
}
|
||||
if(decrypted[0] != (byte)0x69) {
|
||||
throw new IOException("Data is corrupt!");
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if(key != null && key.length > 0) {
|
||||
throw new IOException("Data isn't encrypted!");
|
||||
}
|
||||
decrypted = cookiesTag;
|
||||
decryptedLen = cookiesTag.length;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown type!");
|
||||
}
|
||||
SHA1Digest digest = new SHA1Digest();
|
||||
digest.update(decrypted, 25, decryptedLen - 25);
|
||||
byte[] digestOut = new byte[20];
|
||||
digest.doFinal(digestOut, 0);
|
||||
for(int i = 0; i < 20; ++i) {
|
||||
if(digestOut[i] != decrypted[5 + i]) {
|
||||
throw new IOException("Invalid checksum!");
|
||||
}
|
||||
}
|
||||
int decompressedLen = (decrypted[1] << 24) | (decrypted[2] << 16) | (decrypted[3] << 8) | (decrypted[4] & 0xFF);
|
||||
byte[] decompressed = new byte[decompressedLen];
|
||||
try (InputStream zstream = EaglerZLIB.newInflaterInputStream(new EaglerInputStream(decrypted, 25, decryptedLen - 25))) {
|
||||
int i = 0, j;
|
||||
while(i < decompressedLen && (j = zstream.read(decompressed, i, decompressedLen - i)) != -1) {
|
||||
i += j;
|
||||
}
|
||||
if(i != decompressedLen) {
|
||||
throw new IOException("Length does not match!");
|
||||
}
|
||||
}
|
||||
DataInputStream dis = new DataInputStream(new EaglerInputStream(decompressed));
|
||||
int readCount = dis.readInt();
|
||||
long time = System.currentTimeMillis();
|
||||
for(int i = 0; i < readCount; ++i) {
|
||||
byte flags = dis.readByte();
|
||||
long expires = dis.readLong();
|
||||
int len = dis.readUnsignedShort();
|
||||
String server = dis.readUTF();
|
||||
if(len == 0) {
|
||||
continue;
|
||||
}
|
||||
if(expires < time) {
|
||||
dis.skipBytes(len);
|
||||
continue;
|
||||
}
|
||||
byte[] cookieData = new byte[len];
|
||||
dis.readFully(cookieData);
|
||||
server = normalize(server);
|
||||
dataStore.put(server, new ServerCookie(server, cookieData, expires, (flags & 1) != 0, (flags & 2) != 0));
|
||||
}
|
||||
if(dis.available() > 0) {
|
||||
throw new IOException("Extra bytes remaining!");
|
||||
}
|
||||
}catch (IOException e) {
|
||||
dataStore.clear();
|
||||
PlatformApplication.setLocalStorage(localStorageKey, null, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveData(byte[] key) {
|
||||
Iterator<ServerCookie> itr = dataStore.values().iterator();
|
||||
List<ServerCookie> toSave = new ArrayList<>(dataStore.size());
|
||||
while(itr.hasNext()) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
ServerCookie cookie = itr.next();
|
||||
if(timestamp > cookie.expires || cookie.cookie.length > 255 || cookie.cookie.length == 0) {
|
||||
itr.remove();
|
||||
}else if(cookie.saveCookieToDisk) {
|
||||
toSave.add(cookie);
|
||||
}
|
||||
}
|
||||
if(toSave.size() == 0) {
|
||||
PlatformApplication.setLocalStorage(localStorageKey, null, false);
|
||||
}else {
|
||||
EaglerOutputStream bao = new EaglerOutputStream(1024);
|
||||
bao.skipBytes(25);
|
||||
int totalUncompressedLen;
|
||||
try(DataOutputStream zstream = new DataOutputStream(EaglerZLIB.newDeflaterOutputStream(bao))) {
|
||||
zstream.writeInt(dataStore.size());
|
||||
for(Entry<String,ServerCookie> etr : dataStore.entrySet()) {
|
||||
ServerCookie cookie = etr.getValue();
|
||||
zstream.writeByte((cookie.revokeQuerySupported ? 1 : 0) | (cookie.saveCookieToDisk ? 2 : 0));
|
||||
zstream.writeLong(cookie.expires);
|
||||
zstream.writeShort(cookie.cookie.length);
|
||||
zstream.writeUTF(etr.getKey());
|
||||
zstream.write(cookie.cookie);
|
||||
}
|
||||
totalUncompressedLen = zstream.size();
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to write cookies to local storage!");
|
||||
return;
|
||||
}
|
||||
byte[] toEncrypt = bao.toByteArray();
|
||||
SHA1Digest hash = new SHA1Digest();
|
||||
hash.update(toEncrypt, 25, toEncrypt.length - 25);
|
||||
hash.doFinal(toEncrypt, 5);
|
||||
toEncrypt[1] = (byte)(totalUncompressedLen >>> 24);
|
||||
toEncrypt[2] = (byte)(totalUncompressedLen >>> 16);
|
||||
toEncrypt[3] = (byte)(totalUncompressedLen >>> 8);
|
||||
toEncrypt[4] = (byte)(totalUncompressedLen & 0xFF);
|
||||
if(key != null && key.length > 0) {
|
||||
toEncrypt[0] = (byte)0x69;
|
||||
AESLightEngine aes = new AESLightEngine();
|
||||
aes.init(true, key);
|
||||
int bs = aes.getBlockSize();
|
||||
int blockCount = (toEncrypt.length % bs) != 0 ? (toEncrypt.length / bs + 1) : (toEncrypt.length / bs);
|
||||
byte[] encrypted = new byte[blockCount * bs + 5];
|
||||
encrypted[0] = (byte)2;
|
||||
encrypted[1] = (byte)(toEncrypt.length >>> 24);
|
||||
encrypted[2] = (byte)(toEncrypt.length >>> 16);
|
||||
encrypted[3] = (byte)(toEncrypt.length >>> 8);
|
||||
encrypted[4] = (byte)(toEncrypt.length & 0xFF);
|
||||
byte[] cbcHelper = new byte[] { (byte) 29, (byte) 163, (byte) 4, (byte) 20, (byte) 207, (byte) 26,
|
||||
(byte) 140, (byte) 55, (byte) 246, (byte) 250, (byte) 141, (byte) 183, (byte) 153, (byte) 154,
|
||||
(byte) 59, (byte) 4 };
|
||||
for(int i = 0; i < toEncrypt.length; i += bs) {
|
||||
processBlockEncryptHelper(aes, toEncrypt, i, encrypted, 5 + i, bs, cbcHelper);
|
||||
}
|
||||
PlatformApplication.setLocalStorage(localStorageKey, encrypted, false);
|
||||
}else {
|
||||
toEncrypt[0] = (byte)1;
|
||||
PlatformApplication.setLocalStorage(localStorageKey, toEncrypt, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processBlockEncryptHelper(AESLightEngine aes, byte[] in, int inOff, byte[] out, int outOff,
|
||||
int len, byte[] cbcHelper) {
|
||||
int clampedBlockLength = Math.min(in.length - inOff, len);
|
||||
if(clampedBlockLength == len) {
|
||||
for(int i = 0; i < len; ++i) {
|
||||
in[i + inOff] ^= cbcHelper[i];
|
||||
}
|
||||
aes.processBlock(in, inOff, out, outOff);
|
||||
System.arraycopy(out, outOff, cbcHelper, 0, len);
|
||||
}else {
|
||||
byte[] paddedBlock = new byte[len];
|
||||
System.arraycopy(in, inOff, paddedBlock, 0, clampedBlockLength);
|
||||
byte padValue = (byte)(len - clampedBlockLength);
|
||||
for(byte i = 0; i < padValue; ++i) {
|
||||
paddedBlock[clampedBlockLength + i] = padValue;
|
||||
}
|
||||
for(int i = 0; i < len; ++i) {
|
||||
paddedBlock[i] ^= cbcHelper[i];
|
||||
}
|
||||
aes.processBlock(paddedBlock, 0, out, outOff);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processBlockDecryptHelper(AESLightEngine aes, byte[] in, int inOff, byte[] out, int outOff,
|
||||
int paddedLen, int unpaddedLen, byte[] cbcHelper) throws IOException {
|
||||
aes.processBlock(in, inOff, out, outOff);
|
||||
for(int i = 0; i < paddedLen; ++i) {
|
||||
out[i + outOff] ^= cbcHelper[i];
|
||||
}
|
||||
if(unpaddedLen == paddedLen) {
|
||||
System.arraycopy(in, inOff, cbcHelper, 0, paddedLen);
|
||||
}else {
|
||||
byte padValue = (byte)(paddedLen - unpaddedLen);
|
||||
for(byte i = 0; i < padValue; ++i) {
|
||||
if(out[outOff + unpaddedLen + i] != padValue) {
|
||||
throw new IOException("Invalid padding!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.crypto;
|
||||
|
||||
/**
|
||||
* an implementation of the AES (Rijndael), from FIPS-197.
|
||||
* <p>
|
||||
* For further details see: <a href="https://csrc.nist.gov/encryption/aes/">https://csrc.nist.gov/encryption/aes/</a>.
|
||||
*
|
||||
* This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
|
||||
* <a href="https://fp.gladman.plus.com/cryptography_technology/rijndael/">https://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
|
||||
*
|
||||
* There are three levels of tradeoff of speed vs memory
|
||||
* Because java has no preprocessor, they are written as three separate classes from which to choose
|
||||
*
|
||||
* The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
|
||||
* and 4 for decryption.
|
||||
*
|
||||
* The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
|
||||
* adding 12 rotate operations per round to compute the values contained in the other tables from
|
||||
* the contents of the first
|
||||
*
|
||||
* The slowest version uses no static tables at all and computes the values
|
||||
* in each round.
|
||||
* <p>
|
||||
* This file contains the slowest performance version with no static tables
|
||||
* for round precomputation, but it has the smallest foot print.
|
||||
*
|
||||
*/
|
||||
public class AESLightEngine {
|
||||
// The S box
|
||||
private static final byte[] S = { (byte) 99, (byte) 124, (byte) 119, (byte) 123, (byte) 242, (byte) 107, (byte) 111,
|
||||
(byte) 197, (byte) 48, (byte) 1, (byte) 103, (byte) 43, (byte) 254, (byte) 215, (byte) 171, (byte) 118,
|
||||
(byte) 202, (byte) 130, (byte) 201, (byte) 125, (byte) 250, (byte) 89, (byte) 71, (byte) 240, (byte) 173,
|
||||
(byte) 212, (byte) 162, (byte) 175, (byte) 156, (byte) 164, (byte) 114, (byte) 192, (byte) 183, (byte) 253,
|
||||
(byte) 147, (byte) 38, (byte) 54, (byte) 63, (byte) 247, (byte) 204, (byte) 52, (byte) 165, (byte) 229,
|
||||
(byte) 241, (byte) 113, (byte) 216, (byte) 49, (byte) 21, (byte) 4, (byte) 199, (byte) 35, (byte) 195,
|
||||
(byte) 24, (byte) 150, (byte) 5, (byte) 154, (byte) 7, (byte) 18, (byte) 128, (byte) 226, (byte) 235,
|
||||
(byte) 39, (byte) 178, (byte) 117, (byte) 9, (byte) 131, (byte) 44, (byte) 26, (byte) 27, (byte) 110,
|
||||
(byte) 90, (byte) 160, (byte) 82, (byte) 59, (byte) 214, (byte) 179, (byte) 41, (byte) 227, (byte) 47,
|
||||
(byte) 132, (byte) 83, (byte) 209, (byte) 0, (byte) 237, (byte) 32, (byte) 252, (byte) 177, (byte) 91,
|
||||
(byte) 106, (byte) 203, (byte) 190, (byte) 57, (byte) 74, (byte) 76, (byte) 88, (byte) 207, (byte) 208,
|
||||
(byte) 239, (byte) 170, (byte) 251, (byte) 67, (byte) 77, (byte) 51, (byte) 133, (byte) 69, (byte) 249,
|
||||
(byte) 2, (byte) 127, (byte) 80, (byte) 60, (byte) 159, (byte) 168, (byte) 81, (byte) 163, (byte) 64,
|
||||
(byte) 143, (byte) 146, (byte) 157, (byte) 56, (byte) 245, (byte) 188, (byte) 182, (byte) 218, (byte) 33,
|
||||
(byte) 16, (byte) 255, (byte) 243, (byte) 210, (byte) 205, (byte) 12, (byte) 19, (byte) 236, (byte) 95,
|
||||
(byte) 151, (byte) 68, (byte) 23, (byte) 196, (byte) 167, (byte) 126, (byte) 61, (byte) 100, (byte) 93,
|
||||
(byte) 25, (byte) 115, (byte) 96, (byte) 129, (byte) 79, (byte) 220, (byte) 34, (byte) 42, (byte) 144,
|
||||
(byte) 136, (byte) 70, (byte) 238, (byte) 184, (byte) 20, (byte) 222, (byte) 94, (byte) 11, (byte) 219,
|
||||
(byte) 224, (byte) 50, (byte) 58, (byte) 10, (byte) 73, (byte) 6, (byte) 36, (byte) 92, (byte) 194,
|
||||
(byte) 211, (byte) 172, (byte) 98, (byte) 145, (byte) 149, (byte) 228, (byte) 121, (byte) 231, (byte) 200,
|
||||
(byte) 55, (byte) 109, (byte) 141, (byte) 213, (byte) 78, (byte) 169, (byte) 108, (byte) 86, (byte) 244,
|
||||
(byte) 234, (byte) 101, (byte) 122, (byte) 174, (byte) 8, (byte) 186, (byte) 120, (byte) 37, (byte) 46,
|
||||
(byte) 28, (byte) 166, (byte) 180, (byte) 198, (byte) 232, (byte) 221, (byte) 116, (byte) 31, (byte) 75,
|
||||
(byte) 189, (byte) 139, (byte) 138, (byte) 112, (byte) 62, (byte) 181, (byte) 102, (byte) 72, (byte) 3,
|
||||
(byte) 246, (byte) 14, (byte) 97, (byte) 53, (byte) 87, (byte) 185, (byte) 134, (byte) 193, (byte) 29,
|
||||
(byte) 158, (byte) 225, (byte) 248, (byte) 152, (byte) 17, (byte) 105, (byte) 217, (byte) 142, (byte) 148,
|
||||
(byte) 155, (byte) 30, (byte) 135, (byte) 233, (byte) 206, (byte) 85, (byte) 40, (byte) 223, (byte) 140,
|
||||
(byte) 161, (byte) 137, (byte) 13, (byte) 191, (byte) 230, (byte) 66, (byte) 104, (byte) 65, (byte) 153,
|
||||
(byte) 45, (byte) 15, (byte) 176, (byte) 84, (byte) 187, (byte) 22, };
|
||||
|
||||
// The inverse S-box
|
||||
private static final byte[] Si = { (byte) 82, (byte) 9, (byte) 106, (byte) 213, (byte) 48, (byte) 54, (byte) 165,
|
||||
(byte) 56, (byte) 191, (byte) 64, (byte) 163, (byte) 158, (byte) 129, (byte) 243, (byte) 215, (byte) 251,
|
||||
(byte) 124, (byte) 227, (byte) 57, (byte) 130, (byte) 155, (byte) 47, (byte) 255, (byte) 135, (byte) 52,
|
||||
(byte) 142, (byte) 67, (byte) 68, (byte) 196, (byte) 222, (byte) 233, (byte) 203, (byte) 84, (byte) 123,
|
||||
(byte) 148, (byte) 50, (byte) 166, (byte) 194, (byte) 35, (byte) 61, (byte) 238, (byte) 76, (byte) 149,
|
||||
(byte) 11, (byte) 66, (byte) 250, (byte) 195, (byte) 78, (byte) 8, (byte) 46, (byte) 161, (byte) 102,
|
||||
(byte) 40, (byte) 217, (byte) 36, (byte) 178, (byte) 118, (byte) 91, (byte) 162, (byte) 73, (byte) 109,
|
||||
(byte) 139, (byte) 209, (byte) 37, (byte) 114, (byte) 248, (byte) 246, (byte) 100, (byte) 134, (byte) 104,
|
||||
(byte) 152, (byte) 22, (byte) 212, (byte) 164, (byte) 92, (byte) 204, (byte) 93, (byte) 101, (byte) 182,
|
||||
(byte) 146, (byte) 108, (byte) 112, (byte) 72, (byte) 80, (byte) 253, (byte) 237, (byte) 185, (byte) 218,
|
||||
(byte) 94, (byte) 21, (byte) 70, (byte) 87, (byte) 167, (byte) 141, (byte) 157, (byte) 132, (byte) 144,
|
||||
(byte) 216, (byte) 171, (byte) 0, (byte) 140, (byte) 188, (byte) 211, (byte) 10, (byte) 247, (byte) 228,
|
||||
(byte) 88, (byte) 5, (byte) 184, (byte) 179, (byte) 69, (byte) 6, (byte) 208, (byte) 44, (byte) 30,
|
||||
(byte) 143, (byte) 202, (byte) 63, (byte) 15, (byte) 2, (byte) 193, (byte) 175, (byte) 189, (byte) 3,
|
||||
(byte) 1, (byte) 19, (byte) 138, (byte) 107, (byte) 58, (byte) 145, (byte) 17, (byte) 65, (byte) 79,
|
||||
(byte) 103, (byte) 220, (byte) 234, (byte) 151, (byte) 242, (byte) 207, (byte) 206, (byte) 240, (byte) 180,
|
||||
(byte) 230, (byte) 115, (byte) 150, (byte) 172, (byte) 116, (byte) 34, (byte) 231, (byte) 173, (byte) 53,
|
||||
(byte) 133, (byte) 226, (byte) 249, (byte) 55, (byte) 232, (byte) 28, (byte) 117, (byte) 223, (byte) 110,
|
||||
(byte) 71, (byte) 241, (byte) 26, (byte) 113, (byte) 29, (byte) 41, (byte) 197, (byte) 137, (byte) 111,
|
||||
(byte) 183, (byte) 98, (byte) 14, (byte) 170, (byte) 24, (byte) 190, (byte) 27, (byte) 252, (byte) 86,
|
||||
(byte) 62, (byte) 75, (byte) 198, (byte) 210, (byte) 121, (byte) 32, (byte) 154, (byte) 219, (byte) 192,
|
||||
(byte) 254, (byte) 120, (byte) 205, (byte) 90, (byte) 244, (byte) 31, (byte) 221, (byte) 168, (byte) 51,
|
||||
(byte) 136, (byte) 7, (byte) 199, (byte) 49, (byte) 177, (byte) 18, (byte) 16, (byte) 89, (byte) 39,
|
||||
(byte) 128, (byte) 236, (byte) 95, (byte) 96, (byte) 81, (byte) 127, (byte) 169, (byte) 25, (byte) 181,
|
||||
(byte) 74, (byte) 13, (byte) 45, (byte) 229, (byte) 122, (byte) 159, (byte) 147, (byte) 201, (byte) 156,
|
||||
(byte) 239, (byte) 160, (byte) 224, (byte) 59, (byte) 77, (byte) 174, (byte) 42, (byte) 245, (byte) 176,
|
||||
(byte) 200, (byte) 235, (byte) 187, (byte) 60, (byte) 131, (byte) 83, (byte) 153, (byte) 97, (byte) 23,
|
||||
(byte) 43, (byte) 4, (byte) 126, (byte) 186, (byte) 119, (byte) 214, (byte) 38, (byte) 225, (byte) 105,
|
||||
(byte) 20, (byte) 99, (byte) 85, (byte) 33, (byte) 12, (byte) 125, };
|
||||
|
||||
// vector used in calculating key schedule (powers of x in GF(256))
|
||||
private static final int[] rcon = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,
|
||||
0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
|
||||
|
||||
private static int shift(int r, int shift) {
|
||||
return (r >>> shift) | (r << -shift);
|
||||
}
|
||||
|
||||
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
|
||||
|
||||
private static final int m1 = 0x80808080;
|
||||
private static final int m2 = 0x7f7f7f7f;
|
||||
private static final int m3 = 0x0000001b;
|
||||
private static final int m4 = 0xC0C0C0C0;
|
||||
private static final int m5 = 0x3f3f3f3f;
|
||||
|
||||
private static int FFmulX(int x) {
|
||||
return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
|
||||
}
|
||||
|
||||
private static int FFmulX2(int x) {
|
||||
int t0 = (x & m5) << 2;
|
||||
int t1 = (x & m4);
|
||||
t1 ^= (t1 >>> 1);
|
||||
return t0 ^ (t1 >>> 2) ^ (t1 >>> 5);
|
||||
}
|
||||
|
||||
/*
|
||||
The following defines provide alternative definitions of FFmulX that might
|
||||
give improved performance if a fast 32-bit multiply is not available.
|
||||
|
||||
private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
|
||||
private static final int m4 = 0x1b1b1b1b;
|
||||
private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
|
||||
|
||||
*/
|
||||
|
||||
private static int mcol(int x) {
|
||||
int t0, t1;
|
||||
t0 = shift(x, 8);
|
||||
t1 = x ^ t0;
|
||||
return shift(t1, 16) ^ t0 ^ FFmulX(t1);
|
||||
}
|
||||
|
||||
private static int inv_mcol(int x) {
|
||||
int t0, t1;
|
||||
t0 = x;
|
||||
t1 = t0 ^ shift(t0, 8);
|
||||
t0 ^= FFmulX(t1);
|
||||
t1 ^= FFmulX2(t0);
|
||||
t0 ^= t1 ^ shift(t1, 16);
|
||||
return t0;
|
||||
}
|
||||
|
||||
private static int subWord(int x) {
|
||||
return (S[x & 255] & 255 | ((S[(x >> 8) & 255] & 255) << 8) | ((S[(x >> 16) & 255] & 255) << 16)
|
||||
| S[(x >> 24) & 255] << 24);
|
||||
}
|
||||
|
||||
private static int littleEndianToInt(byte[] bs, int off) {
|
||||
int n = bs[off] & 0xff;
|
||||
n |= (bs[++off] & 0xff) << 8;
|
||||
n |= (bs[++off] & 0xff) << 16;
|
||||
n |= bs[++off] << 24;
|
||||
return n;
|
||||
}
|
||||
|
||||
public static void intToLittleEndian(int n, byte[] bs, int off) {
|
||||
bs[off] = (byte) (n);
|
||||
bs[++off] = (byte) (n >>> 8);
|
||||
bs[++off] = (byte) (n >>> 16);
|
||||
bs[++off] = (byte) (n >>> 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the necessary round keys
|
||||
* The number of calculations depends on key size and block size
|
||||
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
|
||||
* This code is written assuming those are the only possible values
|
||||
*/
|
||||
private int[][] generateWorkingKey(byte[] key, boolean forEncryption) {
|
||||
int keyLen = key.length;
|
||||
if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) {
|
||||
throw new IllegalArgumentException("Key length not 128/192/256 bits.");
|
||||
}
|
||||
|
||||
int KC = keyLen >>> 2;
|
||||
ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block
|
||||
// sizes
|
||||
int[][] W = new int[ROUNDS + 1][4]; // 4 words in a block
|
||||
|
||||
switch (KC) {
|
||||
case 4: {
|
||||
int col0 = littleEndianToInt(key, 0);
|
||||
W[0][0] = col0;
|
||||
int col1 = littleEndianToInt(key, 4);
|
||||
W[0][1] = col1;
|
||||
int col2 = littleEndianToInt(key, 8);
|
||||
W[0][2] = col2;
|
||||
int col3 = littleEndianToInt(key, 12);
|
||||
W[0][3] = col3;
|
||||
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
int colx = subWord(shift(col3, 8)) ^ rcon[i - 1];
|
||||
col0 ^= colx;
|
||||
W[i][0] = col0;
|
||||
col1 ^= col0;
|
||||
W[i][1] = col1;
|
||||
col2 ^= col1;
|
||||
W[i][2] = col2;
|
||||
col3 ^= col2;
|
||||
W[i][3] = col3;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
int col0 = littleEndianToInt(key, 0);
|
||||
W[0][0] = col0;
|
||||
int col1 = littleEndianToInt(key, 4);
|
||||
W[0][1] = col1;
|
||||
int col2 = littleEndianToInt(key, 8);
|
||||
W[0][2] = col2;
|
||||
int col3 = littleEndianToInt(key, 12);
|
||||
W[0][3] = col3;
|
||||
|
||||
int col4 = littleEndianToInt(key, 16);
|
||||
int col5 = littleEndianToInt(key, 20);
|
||||
|
||||
int i = 1, rcon = 1, colx;
|
||||
for (;;) {
|
||||
W[i][0] = col4;
|
||||
W[i][1] = col5;
|
||||
colx = subWord(shift(col5, 8)) ^ rcon;
|
||||
rcon <<= 1;
|
||||
col0 ^= colx;
|
||||
W[i][2] = col0;
|
||||
col1 ^= col0;
|
||||
W[i][3] = col1;
|
||||
|
||||
col2 ^= col1;
|
||||
W[i + 1][0] = col2;
|
||||
col3 ^= col2;
|
||||
W[i + 1][1] = col3;
|
||||
col4 ^= col3;
|
||||
W[i + 1][2] = col4;
|
||||
col5 ^= col4;
|
||||
W[i + 1][3] = col5;
|
||||
|
||||
colx = subWord(shift(col5, 8)) ^ rcon;
|
||||
rcon <<= 1;
|
||||
col0 ^= colx;
|
||||
W[i + 2][0] = col0;
|
||||
col1 ^= col0;
|
||||
W[i + 2][1] = col1;
|
||||
col2 ^= col1;
|
||||
W[i + 2][2] = col2;
|
||||
col3 ^= col2;
|
||||
W[i + 2][3] = col3;
|
||||
|
||||
if ((i += 3) >= 13) {
|
||||
break;
|
||||
}
|
||||
|
||||
col4 ^= col3;
|
||||
col5 ^= col4;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int col0 = littleEndianToInt(key, 0);
|
||||
W[0][0] = col0;
|
||||
int col1 = littleEndianToInt(key, 4);
|
||||
W[0][1] = col1;
|
||||
int col2 = littleEndianToInt(key, 8);
|
||||
W[0][2] = col2;
|
||||
int col3 = littleEndianToInt(key, 12);
|
||||
W[0][3] = col3;
|
||||
|
||||
int col4 = littleEndianToInt(key, 16);
|
||||
W[1][0] = col4;
|
||||
int col5 = littleEndianToInt(key, 20);
|
||||
W[1][1] = col5;
|
||||
int col6 = littleEndianToInt(key, 24);
|
||||
W[1][2] = col6;
|
||||
int col7 = littleEndianToInt(key, 28);
|
||||
W[1][3] = col7;
|
||||
|
||||
int i = 2, rcon = 1, colx;
|
||||
for (;;) {
|
||||
colx = subWord(shift(col7, 8)) ^ rcon;
|
||||
rcon <<= 1;
|
||||
col0 ^= colx;
|
||||
W[i][0] = col0;
|
||||
col1 ^= col0;
|
||||
W[i][1] = col1;
|
||||
col2 ^= col1;
|
||||
W[i][2] = col2;
|
||||
col3 ^= col2;
|
||||
W[i][3] = col3;
|
||||
++i;
|
||||
|
||||
if (i >= 15) {
|
||||
break;
|
||||
}
|
||||
|
||||
colx = subWord(col3);
|
||||
col4 ^= colx;
|
||||
W[i][0] = col4;
|
||||
col5 ^= col4;
|
||||
W[i][1] = col5;
|
||||
col6 ^= col5;
|
||||
W[i][2] = col6;
|
||||
col7 ^= col6;
|
||||
W[i][3] = col7;
|
||||
++i;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException("Should never get here");
|
||||
}
|
||||
}
|
||||
|
||||
if (!forEncryption) {
|
||||
for (int j = 1; j < ROUNDS; j++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
W[j][i] = inv_mcol(W[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return W;
|
||||
}
|
||||
|
||||
private int ROUNDS;
|
||||
private int[][] WorkingKey = null;
|
||||
private boolean forEncryption;
|
||||
|
||||
private static final int BLOCK_SIZE = 16;
|
||||
|
||||
/**
|
||||
* default constructor - 128 bit block size.
|
||||
*/
|
||||
public AESLightEngine() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise an AES cipher.
|
||||
*
|
||||
* @param forEncryption whether or not we are for encryption.
|
||||
* @param params the parameters required to set up the cipher.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(boolean forEncryption, byte[] key) {
|
||||
WorkingKey = generateWorkingKey(key, forEncryption);
|
||||
this.forEncryption = forEncryption;
|
||||
return;
|
||||
}
|
||||
|
||||
public String getAlgorithmName() {
|
||||
return "AES";
|
||||
}
|
||||
|
||||
public int getBlockSize() {
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
public int processBlock(byte[] in, int inOff, byte[] out, int outOff) {
|
||||
if (WorkingKey == null) {
|
||||
throw new IllegalStateException("AES engine not initialised");
|
||||
}
|
||||
|
||||
if (inOff > (in.length - BLOCK_SIZE)) {
|
||||
throw new IndexOutOfBoundsException("input buffer too short");
|
||||
}
|
||||
|
||||
if (outOff > (out.length - BLOCK_SIZE)) {
|
||||
throw new IndexOutOfBoundsException("output buffer too short");
|
||||
}
|
||||
|
||||
if (forEncryption) {
|
||||
encryptBlock(in, inOff, out, outOff, WorkingKey);
|
||||
} else {
|
||||
decryptBlock(in, inOff, out, outOff, WorkingKey);
|
||||
}
|
||||
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
private void encryptBlock(byte[] in, int inOff, byte[] out, int outOff, int[][] KW) {
|
||||
int C0 = littleEndianToInt(in, inOff + 0);
|
||||
int C1 = littleEndianToInt(in, inOff + 4);
|
||||
int C2 = littleEndianToInt(in, inOff + 8);
|
||||
int C3 = littleEndianToInt(in, inOff + 12);
|
||||
|
||||
int t0 = C0 ^ KW[0][0];
|
||||
int t1 = C1 ^ KW[0][1];
|
||||
int t2 = C2 ^ KW[0][2];
|
||||
|
||||
int r = 1, r0, r1, r2, r3 = C3 ^ KW[0][3];
|
||||
while (r < ROUNDS - 1) {
|
||||
r0 = mcol((S[t0 & 255] & 255) ^ ((S[(t1 >> 8) & 255] & 255) << 8) ^ ((S[(t2 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r3 >> 24) & 255] << 24)) ^ KW[r][0];
|
||||
r1 = mcol((S[t1 & 255] & 255) ^ ((S[(t2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(t0 >> 24) & 255] << 24)) ^ KW[r][1];
|
||||
r2 = mcol((S[t2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(t0 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(t1 >> 24) & 255] << 24)) ^ KW[r][2];
|
||||
r3 = mcol((S[r3 & 255] & 255) ^ ((S[(t0 >> 8) & 255] & 255) << 8) ^ ((S[(t1 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(t2 >> 24) & 255] << 24)) ^ KW[r++][3];
|
||||
t0 = mcol((S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r3 >> 24) & 255] << 24)) ^ KW[r][0];
|
||||
t1 = mcol((S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r0 >> 24) & 255] << 24)) ^ KW[r][1];
|
||||
t2 = mcol((S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r1 >> 24) & 255] << 24)) ^ KW[r][2];
|
||||
r3 = mcol((S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r2 >> 24) & 255] << 24)) ^ KW[r++][3];
|
||||
}
|
||||
|
||||
r0 = mcol((S[t0 & 255] & 255) ^ ((S[(t1 >> 8) & 255] & 255) << 8) ^ ((S[(t2 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r3 >> 24) & 255] << 24)) ^ KW[r][0];
|
||||
r1 = mcol((S[t1 & 255] & 255) ^ ((S[(t2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(t0 >> 24) & 255] << 24)) ^ KW[r][1];
|
||||
r2 = mcol((S[t2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(t0 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(t1 >> 24) & 255] << 24)) ^ KW[r][2];
|
||||
r3 = mcol((S[r3 & 255] & 255) ^ ((S[(t0 >> 8) & 255] & 255) << 8) ^ ((S[(t1 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(t2 >> 24) & 255] << 24)) ^ KW[r++][3];
|
||||
|
||||
// the final round is a simple function of S
|
||||
|
||||
C0 = (S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r3 >> 24) & 255] << 24) ^ KW[r][0];
|
||||
C1 = (S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r0 >> 24) & 255] << 24) ^ KW[r][1];
|
||||
C2 = (S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r1 >> 24) & 255] << 24) ^ KW[r][2];
|
||||
C3 = (S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16)
|
||||
^ (S[(r2 >> 24) & 255] << 24) ^ KW[r][3];
|
||||
|
||||
intToLittleEndian(C0, out, outOff + 0);
|
||||
intToLittleEndian(C1, out, outOff + 4);
|
||||
intToLittleEndian(C2, out, outOff + 8);
|
||||
intToLittleEndian(C3, out, outOff + 12);
|
||||
}
|
||||
|
||||
private void decryptBlock(byte[] in, int inOff, byte[] out, int outOff, int[][] KW) {
|
||||
int C0 = littleEndianToInt(in, inOff + 0);
|
||||
int C1 = littleEndianToInt(in, inOff + 4);
|
||||
int C2 = littleEndianToInt(in, inOff + 8);
|
||||
int C3 = littleEndianToInt(in, inOff + 12);
|
||||
|
||||
int t0 = C0 ^ KW[ROUNDS][0];
|
||||
int t1 = C1 ^ KW[ROUNDS][1];
|
||||
int t2 = C2 ^ KW[ROUNDS][2];
|
||||
|
||||
int r = ROUNDS - 1, r0, r1, r2, r3 = C3 ^ KW[ROUNDS][3];
|
||||
while (r > 1) {
|
||||
r0 = inv_mcol((Si[t0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(t2 >> 16) & 255] & 255) << 16) ^ (Si[(t1 >> 24) & 255] << 24)) ^ KW[r][0];
|
||||
r1 = inv_mcol((Si[t1 & 255] & 255) ^ ((Si[(t0 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(r3 >> 16) & 255] & 255) << 16) ^ (Si[(t2 >> 24) & 255] << 24)) ^ KW[r][1];
|
||||
r2 = inv_mcol((Si[t2 & 255] & 255) ^ ((Si[(t1 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(t0 >> 16) & 255] & 255) << 16) ^ (Si[(r3 >> 24) & 255] << 24)) ^ KW[r][2];
|
||||
r3 = inv_mcol((Si[r3 & 255] & 255) ^ ((Si[(t2 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(t1 >> 16) & 255] & 255) << 16) ^ (Si[(t0 >> 24) & 255] << 24)) ^ KW[r--][3];
|
||||
t0 = inv_mcol((Si[r0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(r2 >> 16) & 255] & 255) << 16) ^ (Si[(r1 >> 24) & 255] << 24)) ^ KW[r][0];
|
||||
t1 = inv_mcol((Si[r1 & 255] & 255) ^ ((Si[(r0 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(r3 >> 16) & 255] & 255) << 16) ^ (Si[(r2 >> 24) & 255] << 24)) ^ KW[r][1];
|
||||
t2 = inv_mcol((Si[r2 & 255] & 255) ^ ((Si[(r1 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(r0 >> 16) & 255] & 255) << 16) ^ (Si[(r3 >> 24) & 255] << 24)) ^ KW[r][2];
|
||||
r3 = inv_mcol((Si[r3 & 255] & 255) ^ ((Si[(r2 >> 8) & 255] & 255) << 8)
|
||||
^ ((Si[(r1 >> 16) & 255] & 255) << 16) ^ (Si[(r0 >> 24) & 255] << 24)) ^ KW[r--][3];
|
||||
}
|
||||
|
||||
r0 = inv_mcol((Si[t0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8) ^ ((Si[(t2 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(t1 >> 24) & 255] << 24)) ^ KW[r][0];
|
||||
r1 = inv_mcol((Si[t1 & 255] & 255) ^ ((Si[(t0 >> 8) & 255] & 255) << 8) ^ ((Si[(r3 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(t2 >> 24) & 255] << 24)) ^ KW[r][1];
|
||||
r2 = inv_mcol((Si[t2 & 255] & 255) ^ ((Si[(t1 >> 8) & 255] & 255) << 8) ^ ((Si[(t0 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(r3 >> 24) & 255] << 24)) ^ KW[r][2];
|
||||
r3 = inv_mcol((Si[r3 & 255] & 255) ^ ((Si[(t2 >> 8) & 255] & 255) << 8) ^ ((Si[(t1 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(t0 >> 24) & 255] << 24)) ^ KW[r][3];
|
||||
|
||||
// the final round's table is a simple function of Si
|
||||
|
||||
C0 = (Si[r0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8) ^ ((Si[(r2 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(r1 >> 24) & 255] << 24) ^ KW[0][0];
|
||||
C1 = (Si[r1 & 255] & 255) ^ ((Si[(r0 >> 8) & 255] & 255) << 8) ^ ((Si[(r3 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(r2 >> 24) & 255] << 24) ^ KW[0][1];
|
||||
C2 = (Si[r2 & 255] & 255) ^ ((Si[(r1 >> 8) & 255] & 255) << 8) ^ ((Si[(r0 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(r3 >> 24) & 255] << 24) ^ KW[0][2];
|
||||
C3 = (Si[r3 & 255] & 255) ^ ((Si[(r2 >> 8) & 255] & 255) << 8) ^ ((Si[(r1 >> 16) & 255] & 255) << 16)
|
||||
^ (Si[(r0 >> 24) & 255] << 24) ^ KW[0][3];
|
||||
|
||||
intToLittleEndian(C0, out, outOff + 0);
|
||||
intToLittleEndian(C1, out, outOff + 4);
|
||||
intToLittleEndian(C2, out, outOff + 8);
|
||||
intToLittleEndian(C3, out, outOff + 12);
|
||||
}
|
||||
|
||||
private int bitsOfSecurity() {
|
||||
if (WorkingKey == null) {
|
||||
return 256;
|
||||
}
|
||||
return (WorkingKey.length - 7) << 5;
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ import java.util.concurrent.Executor;
|
||||
*/
|
||||
public class ListenableFutureTask<V> extends FutureTask<V> implements ListenableFuture<V> {
|
||||
|
||||
private final List<Runnable> listeners = new ArrayList();
|
||||
private final List<Runnable> listeners = new ArrayList<>();
|
||||
|
||||
public ListenableFutureTask(Callable<V> callable) {
|
||||
super(callable);
|
||||
@ -54,7 +54,7 @@ public class ListenableFutureTask<V> extends FutureTask<V> implements Listenable
|
||||
}
|
||||
|
||||
public static <V> ListenableFutureTask<V> create(Callable<V> callableToSchedule) {
|
||||
return new ListenableFutureTask(callableToSchedule);
|
||||
return new ListenableFutureTask<>(callableToSchedule);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,227 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 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 abstract class AbstractWebSocketClient implements IWebSocketClient {
|
||||
|
||||
protected volatile int availableStringFrames = 0;
|
||||
protected volatile int availableBinaryFrames = 0;
|
||||
protected final List<IWebSocketFrame> recievedPacketBuffer = new LinkedList<>();
|
||||
protected String currentURI;
|
||||
|
||||
protected AbstractWebSocketClient(String currentURI) {
|
||||
this.currentURI = currentURI;
|
||||
}
|
||||
|
||||
protected void addRecievedFrame(IWebSocketFrame frame) {
|
||||
boolean str = frame.isString();
|
||||
synchronized(recievedPacketBuffer) {
|
||||
recievedPacketBuffer.add(frame);
|
||||
if(str) {
|
||||
++availableStringFrames;
|
||||
}else {
|
||||
++availableBinaryFrames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
return availableStringFrames + availableBinaryFrames;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWebSocketFrame getNextFrame() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(!recievedPacketBuffer.isEmpty()) {
|
||||
IWebSocketFrame frame = recievedPacketBuffer.remove(0);
|
||||
if(frame.isString()) {
|
||||
--availableStringFrames;
|
||||
}else {
|
||||
--availableBinaryFrames;
|
||||
}
|
||||
return frame;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IWebSocketFrame> getNextFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(!recievedPacketBuffer.isEmpty()) {
|
||||
List<IWebSocketFrame> ret = new ArrayList<>(recievedPacketBuffer);
|
||||
recievedPacketBuffer.clear();
|
||||
availableStringFrames = 0;
|
||||
availableBinaryFrames = 0;
|
||||
return ret;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
recievedPacketBuffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableStringFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
return availableStringFrames;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWebSocketFrame getNextStringFrame() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(availableStringFrames > 0) {
|
||||
Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
|
||||
while(itr.hasNext()) {
|
||||
IWebSocketFrame r = itr.next();
|
||||
if(r.isString()) {
|
||||
itr.remove();
|
||||
--availableStringFrames;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
availableStringFrames = 0;
|
||||
return null;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IWebSocketFrame> getNextStringFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(availableStringFrames > 0) {
|
||||
List<IWebSocketFrame> ret = new ArrayList<>(availableStringFrames);
|
||||
Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
|
||||
while(itr.hasNext()) {
|
||||
IWebSocketFrame r = itr.next();
|
||||
if(r.isString()) {
|
||||
itr.remove();
|
||||
ret.add(r);
|
||||
}
|
||||
}
|
||||
availableStringFrames = 0;
|
||||
return ret;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearStringFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(availableStringFrames > 0) {
|
||||
Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
|
||||
while(itr.hasNext()) {
|
||||
IWebSocketFrame r = itr.next();
|
||||
if(r.isString()) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
availableStringFrames = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableBinaryFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
return availableBinaryFrames;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWebSocketFrame getNextBinaryFrame() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(availableBinaryFrames > 0) {
|
||||
Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
|
||||
while(itr.hasNext()) {
|
||||
IWebSocketFrame r = itr.next();
|
||||
if(!r.isString()) {
|
||||
itr.remove();
|
||||
--availableBinaryFrames;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
availableBinaryFrames = 0;
|
||||
return null;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IWebSocketFrame> getNextBinaryFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(availableBinaryFrames > 0) {
|
||||
List<IWebSocketFrame> ret = new ArrayList<>(availableBinaryFrames);
|
||||
Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
|
||||
while(itr.hasNext()) {
|
||||
IWebSocketFrame r = itr.next();
|
||||
if(!r.isString()) {
|
||||
itr.remove();
|
||||
ret.add(r);
|
||||
}
|
||||
}
|
||||
availableBinaryFrames = 0;
|
||||
return ret;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBinaryFrames() {
|
||||
synchronized(recievedPacketBuffer) {
|
||||
if(availableBinaryFrames > 0) {
|
||||
Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
|
||||
while(itr.hasNext()) {
|
||||
IWebSocketFrame r = itr.next();
|
||||
if(!r.isString()) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
availableBinaryFrames = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentURI() {
|
||||
return currentURI;
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 lax1dude. 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 +15,21 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformBufferFunctions {
|
||||
|
||||
public static void put(ByteBuffer newBuffer, ByteBuffer flip) {
|
||||
newBuffer.put(flip);
|
||||
public class EaglerMissingResourceException extends RuntimeException {
|
||||
|
||||
public EaglerMissingResourceException() {
|
||||
}
|
||||
|
||||
public static void put(IntBuffer intBuffer, int index, int[] data) {
|
||||
int p = intBuffer.position();
|
||||
intBuffer.position(index);
|
||||
intBuffer.put(data);
|
||||
intBuffer.position(p);
|
||||
public EaglerMissingResourceException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
|
||||
public EaglerMissingResourceException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public EaglerMissingResourceException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
/**
|
||||
* 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 enum EnumFireKeyboardEvent {
|
||||
KEY_DOWN, KEY_UP, KEY_REPEAT;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
/**
|
||||
* 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 enum EnumFireMouseEvent {
|
||||
MOUSE_DOWN, MOUSE_UP, MOUSE_MOVE, MOUSE_WHEEL;
|
||||
}
|
@ -18,6 +18,7 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
public enum EnumPlatformANGLE {
|
||||
|
||||
DEFAULT(225281 /* GLFW_ANGLE_PLATFORM_TYPE_NONE */, "default", "Default"),
|
||||
D3D9(225284 /* GLFW_ANGLE_PLATFORM_TYPE_D3D9 */, "d3d9", "Direct3D9"),
|
||||
D3D11(225285 /* GLFW_ANGLE_PLATFORM_TYPE_D3D11 */, "d3d11", "Direct3D11"),
|
||||
OPENGL(225282 /* GLFW_ANGLE_PLATFORM_TYPE_OPENGL */, "opengl", "OpenGL"),
|
||||
OPENGLES(225283 /* GLFW_ANGLE_PLATFORM_TYPE_OPENGLES */, "opengles", "OpenGL ES"),
|
||||
@ -41,6 +42,8 @@ public enum EnumPlatformANGLE {
|
||||
public static EnumPlatformANGLE fromId(String id) {
|
||||
if(id.equals("d3d11") || id.equals("d3d") || id.equals("dx11")) {
|
||||
return D3D11;
|
||||
}else if(id.equals("d3d9") || id.equals("dx9")) {
|
||||
return D3D9;
|
||||
}else if(id.equals("opengl")) {
|
||||
return OPENGL;
|
||||
}else if(id.equals("opengles")) {
|
||||
@ -58,6 +61,8 @@ public enum EnumPlatformANGLE {
|
||||
str = str.toLowerCase();
|
||||
if(str.contains("direct3d11") || str.contains("d3d11")) {
|
||||
return D3D11;
|
||||
}else if(str.contains("direct3d9") || str.contains("d3d9")) {
|
||||
return D3D9;
|
||||
}else if(str.contains("opengl es")) {
|
||||
return OPENGLES;
|
||||
}else if(str.contains("opengl")) {
|
||||
|
@ -35,12 +35,15 @@ public enum EnumPlatformAgent {
|
||||
}
|
||||
|
||||
public static EnumPlatformAgent getFromUA(String ua) {
|
||||
if(ua == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
ua = " " + ua.toLowerCase();
|
||||
if(ua.contains(" edg/")) {
|
||||
return EDGE;
|
||||
}else if(ua.contains(" opr/")) {
|
||||
return OPERA;
|
||||
}else if(ua.contains(" chrome/")) {
|
||||
}else if(ua.contains(" chrome/") || ua.contains(" chromium/")) {
|
||||
return CHROME;
|
||||
}else if(ua.contains(" firefox/")) {
|
||||
return FIREFOX;
|
||||
|
@ -42,6 +42,9 @@ public enum EnumPlatformOS {
|
||||
}
|
||||
|
||||
public static EnumPlatformOS getFromJVM(String osNameProperty) {
|
||||
if(osNameProperty == null) {
|
||||
return OTHER;
|
||||
}
|
||||
osNameProperty = osNameProperty.toLowerCase();
|
||||
if(osNameProperty.contains("chrome")) {
|
||||
return CHROMEBOOK_LINUX;
|
||||
@ -57,6 +60,9 @@ public enum EnumPlatformOS {
|
||||
}
|
||||
|
||||
public static EnumPlatformOS getFromUA(String ua) {
|
||||
if(ua == null) {
|
||||
return OTHER;
|
||||
}
|
||||
ua = " " + ua.toLowerCase();
|
||||
if(ua.contains(" cros")) {
|
||||
return CHROMEBOOK_LINUX;
|
||||
|
@ -1,11 +1,7 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. 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
|
||||
@ -19,27 +15,29 @@ import java.io.IOException;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class IPacket05ClientSuccess extends IPacket {
|
||||
public enum EnumTouchEvent {
|
||||
TOUCHSTART(0), TOUCHMOVE(1), TOUCHEND(2);
|
||||
|
||||
public String clientId;
|
||||
public final int id;
|
||||
|
||||
public IPacket05ClientSuccess() {
|
||||
private EnumTouchEvent(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public IPacket05ClientSuccess(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
clientId = readASCII8(input);
|
||||
}
|
||||
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
writeASCII8(output, clientId);
|
||||
public static EnumTouchEvent getById(int id) {
|
||||
if(id >= 0 && id < lookup.length) {
|
||||
return lookup[id];
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int packetLength() {
|
||||
return 1 + clientId.length();
|
||||
}
|
||||
private static final EnumTouchEvent[] lookup = new EnumTouchEvent[3];
|
||||
|
||||
static {
|
||||
EnumTouchEvent[] v = values();
|
||||
for(int i = 0; i < v.length; ++i) {
|
||||
lookup[v[i].id] = v[i];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
/**
|
||||
* 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 enum EnumWebViewContentMode {
|
||||
URL_BASED, BLOB_BASED;
|
||||
}
|
@ -71,4 +71,11 @@ public class GLObjectMap<T> {
|
||||
values = new Object[size];
|
||||
System.arraycopy(oldValues, 0, values, 0, oldSize);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if(allocatedObjects == 0) return;
|
||||
values = new Object[size];
|
||||
insertIndex = 0;
|
||||
allocatedObjects = 0;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,134 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
/**
|
||||
* 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 GamepadConstants {
|
||||
|
||||
private static final String[] buttonNames = new String[24];
|
||||
private static final String[] axisNames = new String[4];
|
||||
private static final int[] eaglerButtonsToGLFW = new int[24];
|
||||
private static final int[] glfwButtonsToEagler = new int[24];
|
||||
|
||||
public static final int GAMEPAD_NONE = -1;
|
||||
public static final int GAMEPAD_A = 0;
|
||||
public static final int GAMEPAD_B = 1;
|
||||
public static final int GAMEPAD_X = 2;
|
||||
public static final int GAMEPAD_Y = 3;
|
||||
public static final int GAMEPAD_LEFT_BUTTON = 4;
|
||||
public static final int GAMEPAD_RIGHT_BUTTON = 5;
|
||||
public static final int GAMEPAD_LEFT_TRIGGER = 6;
|
||||
public static final int GAMEPAD_RIGHT_TRIGGER = 7;
|
||||
public static final int GAMEPAD_BACK = 8;
|
||||
public static final int GAMEPAD_START = 9;
|
||||
public static final int GAMEPAD_LEFT_STICK_BUTTON = 10;
|
||||
public static final int GAMEPAD_RIGHT_STICK_BUTTON = 11;
|
||||
public static final int GAMEPAD_DPAD_UP = 12;
|
||||
public static final int GAMEPAD_DPAD_DOWN = 13;
|
||||
public static final int GAMEPAD_DPAD_LEFT = 14;
|
||||
public static final int GAMEPAD_DPAD_RIGHT = 15;
|
||||
public static final int GAMEPAD_GUIDE = 16;
|
||||
|
||||
public static final int GAMEPAD_AXIS_NONE = -1;
|
||||
public static final int GAMEPAD_AXIS_LEFT_STICK_X = 0;
|
||||
public static final int GAMEPAD_AXIS_LEFT_STICK_Y = 1;
|
||||
public static final int GAMEPAD_AXIS_RIGHT_STICK_X = 2;
|
||||
public static final int GAMEPAD_AXIS_RIGHT_STICK_Y = 3;
|
||||
|
||||
private static final int GLFW_GAMEPAD_BUTTON_A = 0, GLFW_GAMEPAD_BUTTON_B = 1, GLFW_GAMEPAD_BUTTON_X = 2,
|
||||
GLFW_GAMEPAD_BUTTON_Y = 3, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER = 4, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER = 5,
|
||||
GLFW_GAMEPAD_BUTTON_BACK = 6, GLFW_GAMEPAD_BUTTON_START = 7, GLFW_GAMEPAD_BUTTON_GUIDE = 8,
|
||||
GLFW_GAMEPAD_BUTTON_LEFT_THUMB = 9, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB = 10, GLFW_GAMEPAD_BUTTON_DPAD_UP = 11,
|
||||
GLFW_GAMEPAD_BUTTON_DPAD_RIGHT = 12, GLFW_GAMEPAD_BUTTON_DPAD_DOWN = 13, GLFW_GAMEPAD_BUTTON_DPAD_LEFT = 14;
|
||||
|
||||
private static void registerBtn(int eaglerBtn, int glfwBtn, String name) {
|
||||
if(eaglerButtonsToGLFW[eaglerBtn] != 0) throw new IllegalArgumentException("Duplicate eaglerButtonsToGLFW entry: " + eaglerBtn + " -> " + glfwBtn);
|
||||
if(glfwBtn != -1 && glfwButtonsToEagler[glfwBtn] != 0) throw new IllegalArgumentException("Duplicate glfwButtonsToEAGLER entry: " + glfwBtn + " -> " + eaglerBtn);
|
||||
eaglerButtonsToGLFW[eaglerBtn] = glfwBtn;
|
||||
if(glfwBtn != -1) glfwButtonsToEagler[glfwBtn] = eaglerBtn;
|
||||
if(buttonNames[eaglerBtn] != null) throw new IllegalArgumentException("Duplicate buttonNames entry: " + eaglerBtn);
|
||||
buttonNames[eaglerBtn] = name;
|
||||
}
|
||||
|
||||
private static void registerAxis(int eaglerAxis, String name) {
|
||||
if(axisNames[eaglerAxis] != null) throw new IllegalArgumentException("Duplicate axisNames entry: " + eaglerAxis);
|
||||
axisNames[eaglerAxis] = name;
|
||||
}
|
||||
|
||||
static {
|
||||
registerBtn(GAMEPAD_A, GLFW_GAMEPAD_BUTTON_A, "A");
|
||||
registerBtn(GAMEPAD_B, GLFW_GAMEPAD_BUTTON_B, "B");
|
||||
registerBtn(GAMEPAD_X, GLFW_GAMEPAD_BUTTON_X, "X");
|
||||
registerBtn(GAMEPAD_Y, GLFW_GAMEPAD_BUTTON_Y, "Y");
|
||||
registerBtn(GAMEPAD_LEFT_BUTTON, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, "Left Button");
|
||||
registerBtn(GAMEPAD_LEFT_TRIGGER, -1, "Left Trigger");
|
||||
registerBtn(GAMEPAD_RIGHT_BUTTON, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, "Right Button");
|
||||
registerBtn(GAMEPAD_RIGHT_TRIGGER, -1, "Right Trigger");
|
||||
registerBtn(GAMEPAD_BACK, GLFW_GAMEPAD_BUTTON_BACK, "Back");
|
||||
registerBtn(GAMEPAD_START, GLFW_GAMEPAD_BUTTON_START, "Start");
|
||||
registerBtn(GAMEPAD_LEFT_STICK_BUTTON, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, "L. Stick Button");
|
||||
registerBtn(GAMEPAD_RIGHT_STICK_BUTTON, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, "R. Stick Button");
|
||||
registerBtn(GAMEPAD_DPAD_UP, GLFW_GAMEPAD_BUTTON_DPAD_UP, "D-Pad Up");
|
||||
registerBtn(GAMEPAD_DPAD_DOWN, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, "D-Pad Down");
|
||||
registerBtn(GAMEPAD_DPAD_LEFT, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, "D-Pad Left");
|
||||
registerBtn(GAMEPAD_DPAD_RIGHT, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, "D-Pad Right");
|
||||
registerBtn(GAMEPAD_GUIDE, GLFW_GAMEPAD_BUTTON_GUIDE, "Guide");
|
||||
registerAxis(GAMEPAD_AXIS_LEFT_STICK_X, "Left Stick X");
|
||||
registerAxis(GAMEPAD_AXIS_LEFT_STICK_Y, "Left Stick Y");
|
||||
registerAxis(GAMEPAD_AXIS_RIGHT_STICK_X, "Right Stick X");
|
||||
registerAxis(GAMEPAD_AXIS_RIGHT_STICK_Y, "Right Stick Y");
|
||||
}
|
||||
|
||||
public static int getEaglerButtonFromBrowser(int button) {
|
||||
return button;
|
||||
}
|
||||
|
||||
public static int getBrowserButtonFromEagler(int button) {
|
||||
return button;
|
||||
}
|
||||
|
||||
public static int getEaglerButtonFromGLFW(int button) {
|
||||
if(button >= 0 && button < glfwButtonsToEagler.length) {
|
||||
return glfwButtonsToEagler[button];
|
||||
}else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getGLFWButtonFromEagler(int button) {
|
||||
if(button >= 0 && button < eaglerButtonsToGLFW.length) {
|
||||
return eaglerButtonsToGLFW[button];
|
||||
}else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getButtonName(int button) {
|
||||
if(button >= 0 && button < buttonNames.length) {
|
||||
return buttonNames[button];
|
||||
}else {
|
||||
return "Button " + button;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getAxisName(int button) {
|
||||
if(button >= 0 && button < axisNames.length) {
|
||||
return axisNames[button];
|
||||
}else {
|
||||
return "Axis " + button;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -26,10 +26,12 @@ public interface IClientConfigAdapter {
|
||||
|
||||
public final String name;
|
||||
public final String addr;
|
||||
public final boolean hideAddress;
|
||||
|
||||
public DefaultServer(String name, String addr) {
|
||||
public DefaultServer(String name, String addr, boolean hideAddress) {
|
||||
this.name = name;
|
||||
this.addr = addr;
|
||||
this.hideAddress = hideAddress;
|
||||
}
|
||||
|
||||
}
|
||||
@ -76,6 +78,24 @@ public interface IClientConfigAdapter {
|
||||
|
||||
boolean isEnableMinceraft();
|
||||
|
||||
boolean isEnableServerCookies();
|
||||
|
||||
boolean isAllowServerRedirects();
|
||||
|
||||
boolean isOpenDebugConsoleOnLaunch();
|
||||
|
||||
boolean isForceWebViewSupport();
|
||||
|
||||
boolean isEnableWebViewCSP();
|
||||
|
||||
boolean isAllowBootMenu();
|
||||
|
||||
boolean isForceProfanityFilter();
|
||||
|
||||
boolean isEaglerNoDelay();
|
||||
|
||||
boolean isRamdiskMode();
|
||||
|
||||
IClientConfigAdapterHooks getHooks();
|
||||
|
||||
}
|
||||
|
@ -25,4 +25,6 @@ public interface IClientConfigAdapterHooks {
|
||||
|
||||
void callCrashReportHook(String crashReport, Consumer<String> customMessageCB);
|
||||
|
||||
void callScreenChangedHook(String screenName, int scaledWidth, int scaledHeight, int realWidth, int realHeight, int scaleFactor);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface IEaglerFilesystem {
|
||||
|
||||
String getFilesystemName();
|
||||
|
||||
String getInternalDBName();
|
||||
|
||||
boolean isRamdisk();
|
||||
|
||||
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);
|
||||
|
||||
void closeHandle();
|
||||
|
||||
}
|
@ -2,6 +2,8 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
||||
*
|
||||
@ -42,6 +44,8 @@ public interface IServerQuery {
|
||||
|
||||
}
|
||||
|
||||
void update();
|
||||
|
||||
void send(String str);
|
||||
|
||||
default void send(JSONObject json) {
|
||||
@ -73,8 +77,8 @@ public interface IServerQuery {
|
||||
EnumServerRateLimit getRateLimit();
|
||||
|
||||
default boolean awaitResponseAvailable(long timeout) {
|
||||
long start = System.currentTimeMillis();
|
||||
while(isOpen() && responsesAvailable() <= 0 && (timeout <= 0l || System.currentTimeMillis() - start < timeout)) {
|
||||
long start = EagRuntime.steadyTimeMillis();
|
||||
while(isOpen() && responsesAvailable() <= 0 && (timeout <= 0l || EagRuntime.steadyTimeMillis() - start < timeout)) {
|
||||
try {
|
||||
Thread.sleep(0l, 250000);
|
||||
} catch (InterruptedException e) {
|
||||
@ -88,8 +92,8 @@ public interface IServerQuery {
|
||||
}
|
||||
|
||||
default boolean awaitResponseBinaryAvailable(long timeout) {
|
||||
long start = System.currentTimeMillis();
|
||||
while(isOpen() && binaryResponsesAvailable() <= 0 && (timeout <= 0l || System.currentTimeMillis() - start < timeout)) {
|
||||
long start = EagRuntime.steadyTimeMillis();
|
||||
while(isOpen() && binaryResponsesAvailable() <= 0 && (timeout <= 0l || EagRuntime.steadyTimeMillis() - start < timeout)) {
|
||||
try {
|
||||
Thread.sleep(0l, 250000);
|
||||
} catch (InterruptedException e) {
|
||||
|
@ -1,12 +1,9 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. 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
|
||||
@ -20,31 +17,46 @@ import java.util.List;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class IPacket07LocalWorlds extends IPacket {
|
||||
|
||||
public static class LocalWorld {
|
||||
|
||||
public final String worldName;
|
||||
public final String worldCode;
|
||||
|
||||
public LocalWorld(String worldName, String worldCode) {
|
||||
this.worldName = worldName;
|
||||
this.worldCode = worldCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final List<LocalWorld> worldsList;
|
||||
|
||||
public IPacket07LocalWorlds() {
|
||||
this.worldsList = new ArrayList();
|
||||
}
|
||||
public interface IWebSocketClient {
|
||||
|
||||
EnumEaglerConnectionState getState();
|
||||
|
||||
boolean connectBlocking(int timeoutMS);
|
||||
|
||||
boolean isOpen();
|
||||
|
||||
boolean isClosed();
|
||||
|
||||
void close();
|
||||
|
||||
int availableFrames();
|
||||
|
||||
IWebSocketFrame getNextFrame();
|
||||
|
||||
List<IWebSocketFrame> getNextFrames();
|
||||
|
||||
void clearFrames();
|
||||
|
||||
int availableStringFrames();
|
||||
|
||||
IWebSocketFrame getNextStringFrame();
|
||||
|
||||
List<IWebSocketFrame> getNextStringFrames();
|
||||
|
||||
void clearStringFrames();
|
||||
|
||||
int availableBinaryFrames();
|
||||
|
||||
IWebSocketFrame getNextBinaryFrame();
|
||||
|
||||
List<IWebSocketFrame> getNextBinaryFrames();
|
||||
|
||||
void clearBinaryFrames();
|
||||
|
||||
void send(String str);
|
||||
|
||||
void send(byte[] bytes);
|
||||
|
||||
String getCurrentURI();
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
int l = input.read();
|
||||
for(int i = 0; i < l; ++i) {
|
||||
worldsList.add(new LocalWorld(readASCII8(input), readASCII8(input)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 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,18 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class PlatformBufferFunctions {
|
||||
public interface IWebSocketFrame {
|
||||
|
||||
public static void put(ByteBuffer newBuffer, ByteBuffer flip) {
|
||||
newBuffer.put(flip);
|
||||
}
|
||||
boolean isString();
|
||||
|
||||
String getString();
|
||||
|
||||
byte[] getByteArray();
|
||||
|
||||
InputStream getInputStream();
|
||||
|
||||
int getLength();
|
||||
|
||||
long getTimestamp();
|
||||
|
||||
public static void put(IntBuffer intBuffer, int index, int[] data) {
|
||||
int p = intBuffer.position();
|
||||
intBuffer.position(index);
|
||||
intBuffer.put(data);
|
||||
intBuffer.position(p);
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,8 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
||||
*
|
||||
@ -37,7 +39,7 @@ public class QueryResponse {
|
||||
this.serverBrand = obj.getString("brand");
|
||||
this.serverName = obj.getString("name");
|
||||
this.serverTime = obj.getLong("time");
|
||||
this.clientTime = System.currentTimeMillis();
|
||||
this.clientTime = EagRuntime.steadyTimeMillis();
|
||||
this.serverCracked = obj.optBoolean("cracked", false);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,131 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
|
||||
/**
|
||||
* 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 RamdiskFilesystemImpl implements IEaglerFilesystem {
|
||||
|
||||
protected final String filesystemName;
|
||||
protected final Map<String,byte[]> filesystemMap = new TreeMap<>();
|
||||
|
||||
public RamdiskFilesystemImpl(String filesystemName) {
|
||||
this.filesystemName = filesystemName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilesystemName() {
|
||||
return filesystemName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalDBName() {
|
||||
return "ramdisk:" + filesystemName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRamdisk() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerDelete(String pathName) {
|
||||
return filesystemMap.remove(pathName) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer eaglerRead(String pathName) {
|
||||
byte[] data = filesystemMap.get(pathName);
|
||||
if(data != null) {
|
||||
ByteBuffer buf = PlatformRuntime.castPrimitiveByteArray(data);
|
||||
if(buf == null) {
|
||||
buf = PlatformRuntime.allocateByteBuffer(data.length);
|
||||
buf.put(data);
|
||||
buf.flip();
|
||||
}
|
||||
return buf;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eaglerWrite(String pathName, ByteBuffer data) {
|
||||
byte[] arr = PlatformRuntime.castNativeByteBuffer(data);
|
||||
if(arr == null) {
|
||||
arr = new byte[data.remaining()];
|
||||
int i = data.position();
|
||||
data.get(arr);
|
||||
data.position(i);
|
||||
}
|
||||
filesystemMap.put(pathName, arr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerExists(String pathName) {
|
||||
return filesystemMap.containsKey(pathName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eaglerMove(String pathNameOld, String pathNameNew) {
|
||||
byte[] dat = filesystemMap.remove(pathNameOld);
|
||||
if(dat != null) {
|
||||
filesystemMap.put(pathNameNew, dat);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int eaglerCopy(String pathNameOld, String pathNameNew) {
|
||||
byte[] dat = filesystemMap.get(pathNameOld);
|
||||
if(dat != null) {
|
||||
filesystemMap.put(pathNameNew, dat);
|
||||
return dat.length;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int eaglerSize(String pathName) {
|
||||
byte[] dat = filesystemMap.get(pathName);
|
||||
return dat != null ? dat.length : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
|
||||
if(!recursive) {
|
||||
eaglerIterate(pathName, new VFSFilenameIteratorNonRecursive(itr,
|
||||
VFSFilenameIteratorNonRecursive.countSlashes(pathName) + 1), true);
|
||||
}else {
|
||||
boolean b = pathName.length() == 0;
|
||||
for(String key : filesystemMap.keySet()) {
|
||||
if(b || key.startsWith(pathName)) {
|
||||
itr.next(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHandle() {
|
||||
filesystemMap.clear();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class ScreenRecordParameters {
|
||||
|
||||
public final EnumScreenRecordingCodec codec;
|
||||
public final int resolutionDivisior;
|
||||
public final int videoBitsPerSecond;
|
||||
public final int audioBitsPerSecond;
|
||||
public final int captureFrameRate;
|
||||
|
||||
public ScreenRecordParameters(EnumScreenRecordingCodec codec, int resolutionDivisior, int videoBitsPerSecond,
|
||||
int audioBitsPerSecond, int captureFrameRate) {
|
||||
this.codec = codec;
|
||||
this.resolutionDivisior = resolutionDivisior;
|
||||
this.videoBitsPerSecond = videoBitsPerSecond;
|
||||
this.audioBitsPerSecond = audioBitsPerSecond;
|
||||
this.captureFrameRate = captureFrameRate;
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. 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
|
||||
@ -18,28 +15,33 @@ import java.io.IOException;
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class IPacket69Pong extends IPacket {
|
||||
public class VFSFilenameIteratorNonRecursive implements VFSFilenameIterator {
|
||||
|
||||
public int protcolVersion;
|
||||
public String comment;
|
||||
public String brand;
|
||||
|
||||
public IPacket69Pong(int protcolVersion, String comment, String brand) {
|
||||
if(comment.length() > 255) {
|
||||
comment = comment.substring(0, 256);
|
||||
private final VFSFilenameIterator child;
|
||||
private final int pathCount;
|
||||
|
||||
public VFSFilenameIteratorNonRecursive(VFSFilenameIterator child, int pathCount) {
|
||||
this.child = child;
|
||||
this.pathCount = pathCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(String entry) {
|
||||
int i = countSlashes(entry);
|
||||
if(i == pathCount) {
|
||||
child.next(entry);
|
||||
}
|
||||
this.protcolVersion = protcolVersion;
|
||||
this.comment = comment;
|
||||
this.brand = brand;
|
||||
}
|
||||
|
||||
public IPacket69Pong() {
|
||||
public static int countSlashes(String str) {
|
||||
if(str.length() == 0) return -1;
|
||||
int j = 0;
|
||||
for(int i = 0, l = str.length(); i < l; ++i) {
|
||||
if(str.charAt(i) == '/') {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
public void read(DataInputStream output) throws IOException {
|
||||
protcolVersion = output.read();
|
||||
comment = readASCII8(output);
|
||||
brand = readASCII8(output);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
|
||||
/**
|
||||
* 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 WebViewOptions {
|
||||
|
||||
public EnumWebViewContentMode contentMode = EnumWebViewContentMode.BLOB_BASED;
|
||||
public String fallbackTitle = "WebView";
|
||||
public boolean scriptEnabled = false;
|
||||
public boolean strictCSPEnable = true;
|
||||
public boolean serverMessageAPIEnabled = false;
|
||||
public URI url = null;
|
||||
public byte[] blob = null;
|
||||
public EaglercraftUUID permissionsOriginUUID = null;
|
||||
|
||||
public WebViewOptions() {
|
||||
}
|
||||
|
||||
public WebViewOptions(boolean script, boolean serverMessageAPIEnabled, boolean strictCSPEnable, URI url) {
|
||||
this.contentMode = EnumWebViewContentMode.URL_BASED;
|
||||
this.scriptEnabled = script;
|
||||
this.strictCSPEnable = strictCSPEnable;
|
||||
this.serverMessageAPIEnabled = serverMessageAPIEnabled;
|
||||
this.url = url;
|
||||
this.permissionsOriginUUID = getURLOriginUUID(url);
|
||||
}
|
||||
|
||||
public WebViewOptions(boolean script, boolean serverMessageAPIEnabled, boolean strictCSPEnable, byte[] data, EaglercraftUUID permissionsOriginUUID) {
|
||||
this.contentMode = EnumWebViewContentMode.BLOB_BASED;
|
||||
this.scriptEnabled = script;
|
||||
this.strictCSPEnable = strictCSPEnable;
|
||||
this.serverMessageAPIEnabled = serverMessageAPIEnabled;
|
||||
this.blob = data;
|
||||
this.permissionsOriginUUID = permissionsOriginUUID;
|
||||
}
|
||||
|
||||
public static EaglercraftUUID getURLOriginUUID(URI url) {
|
||||
return EaglercraftUUID.nameUUIDFromBytes(("URLOrigin:" + url.toString()).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static EaglercraftUUID getEmbedOriginUUID(byte[] sha256) {
|
||||
byte[] vigg = "BlobOrigin:".getBytes(StandardCharsets.UTF_8);
|
||||
byte[] eagler = new byte[sha256.length + vigg.length];
|
||||
System.arraycopy(vigg, 0, eagler, 0, vigg.length);
|
||||
System.arraycopy(sha256, 0, eagler, vigg.length, sha256.length);
|
||||
return EaglercraftUUID.nameUUIDFromBytes(eagler);
|
||||
}
|
||||
|
||||
}
|
@ -41,14 +41,14 @@ public interface Buffer {
|
||||
|
||||
boolean hasRemaining();
|
||||
|
||||
boolean isReadOnly();
|
||||
|
||||
boolean hasArray();
|
||||
|
||||
Object array();
|
||||
|
||||
int arrayOffset();
|
||||
|
||||
boolean isDirect();
|
||||
|
||||
static IndexOutOfBoundsException makeIOOBE(int idx) {
|
||||
return new IndexOutOfBoundsException("Index out of range: " + idx);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,12 +18,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
*/
|
||||
public interface ByteBuffer extends Buffer {
|
||||
|
||||
ByteBuffer slice();
|
||||
|
||||
ByteBuffer duplicate();
|
||||
|
||||
ByteBuffer asReadOnlyBuffer();
|
||||
|
||||
byte get();
|
||||
|
||||
ByteBuffer put(byte b);
|
||||
@ -42,10 +38,6 @@ public interface ByteBuffer extends Buffer {
|
||||
|
||||
ByteBuffer put(byte[] src);
|
||||
|
||||
int arrayOffset();
|
||||
|
||||
ByteBuffer compact();
|
||||
|
||||
char getChar();
|
||||
|
||||
ByteBuffer putChar(char value);
|
||||
@ -54,7 +46,7 @@ public interface ByteBuffer extends Buffer {
|
||||
|
||||
ByteBuffer putChar(int index, char value);
|
||||
|
||||
public abstract short getShort();
|
||||
short getShort();
|
||||
|
||||
ByteBuffer putShort(short value);
|
||||
|
||||
@ -106,4 +98,6 @@ public interface ByteBuffer extends Buffer {
|
||||
|
||||
ByteBuffer position(int newPosition);
|
||||
|
||||
byte[] array();
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
||||
*
|
||||
|
@ -17,12 +17,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
*/
|
||||
public interface FloatBuffer extends Buffer {
|
||||
|
||||
FloatBuffer slice();
|
||||
|
||||
FloatBuffer duplicate();
|
||||
|
||||
FloatBuffer asReadOnlyBuffer();
|
||||
|
||||
float get();
|
||||
|
||||
FloatBuffer put(float b);
|
||||
@ -45,10 +41,6 @@ public interface FloatBuffer extends Buffer {
|
||||
|
||||
FloatBuffer put(float[] src);
|
||||
|
||||
int getArrayOffset();
|
||||
|
||||
FloatBuffer compact();
|
||||
|
||||
boolean isDirect();
|
||||
|
||||
FloatBuffer mark();
|
||||
@ -64,6 +56,8 @@ public interface FloatBuffer extends Buffer {
|
||||
FloatBuffer limit(int newLimit);
|
||||
|
||||
FloatBuffer position(int newPosition);
|
||||
|
||||
|
||||
float[] array();
|
||||
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
*/
|
||||
public interface IntBuffer extends Buffer {
|
||||
|
||||
IntBuffer slice();
|
||||
|
||||
IntBuffer duplicate();
|
||||
|
||||
IntBuffer asReadOnlyBuffer();
|
||||
|
||||
int get();
|
||||
|
||||
IntBuffer put(int b);
|
||||
@ -45,10 +41,6 @@ public interface IntBuffer extends Buffer {
|
||||
|
||||
IntBuffer put(int[] src);
|
||||
|
||||
int getArrayOffset();
|
||||
|
||||
IntBuffer compact();
|
||||
|
||||
boolean isDirect();
|
||||
|
||||
IntBuffer mark();
|
||||
@ -64,6 +56,8 @@ public interface IntBuffer extends Buffer {
|
||||
IntBuffer limit(int newLimit);
|
||||
|
||||
IntBuffer position(int newPosition);
|
||||
|
||||
|
||||
int[] array();
|
||||
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
|
||||
*/
|
||||
public interface ShortBuffer extends Buffer {
|
||||
|
||||
ShortBuffer slice();
|
||||
|
||||
ShortBuffer duplicate();
|
||||
|
||||
ShortBuffer asReadOnlyBuffer();
|
||||
|
||||
short get();
|
||||
|
||||
ShortBuffer put(short b);
|
||||
@ -45,10 +41,6 @@ public interface ShortBuffer extends Buffer {
|
||||
|
||||
ShortBuffer put(short[] src);
|
||||
|
||||
int getArrayOffset();
|
||||
|
||||
ShortBuffer compact();
|
||||
|
||||
boolean isDirect();
|
||||
|
||||
ShortBuffer mark();
|
||||
@ -64,5 +56,7 @@ public interface ShortBuffer extends Buffer {
|
||||
ShortBuffer limit(int newLimit);
|
||||
|
||||
ShortBuffer position(int newPosition);
|
||||
|
||||
|
||||
short[] array();
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.internal.vfs2;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
|
||||
/**
|
||||
@ -19,15 +20,17 @@ import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
*/
|
||||
class VFSFilenameIteratorImpl implements VFSFilenameIterator {
|
||||
|
||||
protected IEaglerFilesystem fs;
|
||||
protected VFSIterator2 itr;
|
||||
|
||||
VFSFilenameIteratorImpl(VFSIterator2 itr) {
|
||||
VFSFilenameIteratorImpl(IEaglerFilesystem fs, VFSIterator2 itr) {
|
||||
this.fs = fs;
|
||||
this.itr = itr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(String entry) {
|
||||
itr.next(new VFile2(entry));
|
||||
itr.next(VFile2.create(fs, entry));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.vfs2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
|
||||
/**
|
||||
@ -21,15 +22,17 @@ import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
|
||||
*/
|
||||
class VFSListFilesIteratorImpl implements VFSFilenameIterator {
|
||||
|
||||
protected IEaglerFilesystem fs;
|
||||
protected List<VFile2> list;
|
||||
|
||||
VFSListFilesIteratorImpl(List<VFile2> list) {
|
||||
VFSListFilesIteratorImpl(IEaglerFilesystem fs, List<VFile2> list) {
|
||||
this.fs = fs;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(String entry) {
|
||||
list.add(new VFile2(entry));
|
||||
list.add(VFile2.create(fs, entry));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
|
||||
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;
|
||||
|
||||
@ -31,6 +32,12 @@ public class VFile2 {
|
||||
public static final String pathSeperator = "/";
|
||||
public static final String[] altPathSeperator = new String[] { "\\" };
|
||||
|
||||
static IEaglerFilesystem primaryFilesystem = null;
|
||||
|
||||
public static void setPrimaryFilesystem(IEaglerFilesystem fs) {
|
||||
primaryFilesystem = fs;
|
||||
}
|
||||
|
||||
public static String normalizePath(String p) {
|
||||
for(int i = 0; i < altPathSeperator.length; ++i) {
|
||||
p = p.replace(altPathSeperator[i], pathSeperator);
|
||||
@ -53,9 +60,11 @@ public class VFile2 {
|
||||
}
|
||||
|
||||
protected String path;
|
||||
protected IEaglerFilesystem myFilesystem;
|
||||
protected Supplier<IEaglerFilesystem> myFilesystemProvider;
|
||||
|
||||
public static String createPath(Object... p) {
|
||||
ArrayList<String> r = new ArrayList();
|
||||
ArrayList<String> r = new ArrayList<>();
|
||||
for(int i = 0; i < p.length; ++i) {
|
||||
if(p[i] == null) {
|
||||
continue;
|
||||
@ -94,13 +103,45 @@ public class VFile2 {
|
||||
}
|
||||
}
|
||||
|
||||
public VFile2(Object... p) {
|
||||
this.path = createPath(p);
|
||||
public static VFile2 create(IEaglerFilesystem fs, Object... path) {
|
||||
return new VFile2(createPath(path), fs);
|
||||
}
|
||||
|
||||
public static VFile2 create(Supplier<IEaglerFilesystem> fs, Object... path) {
|
||||
return new VFile2(createPath(path), fs);
|
||||
}
|
||||
|
||||
public VFile2(Object... path) {
|
||||
this(createPath(path), primaryFilesystem);
|
||||
}
|
||||
|
||||
private VFile2(String path, IEaglerFilesystem fs) {
|
||||
this.path = path;
|
||||
this.myFilesystem = fs;
|
||||
}
|
||||
|
||||
private VFile2(String path, Supplier<IEaglerFilesystem> fs) {
|
||||
this.path = path;
|
||||
this.myFilesystemProvider = fs;
|
||||
}
|
||||
|
||||
protected IEaglerFilesystem getFS() {
|
||||
if(myFilesystem == null) {
|
||||
if(myFilesystemProvider != null) {
|
||||
myFilesystem = myFilesystemProvider.get();
|
||||
}else {
|
||||
myFilesystem = primaryFilesystem;
|
||||
}
|
||||
if(myFilesystem == null) {
|
||||
throw new IllegalStateException("The filesystem has not been initialized yet!");
|
||||
}
|
||||
}
|
||||
return myFilesystem;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
assertNotRelative();
|
||||
return new VFileInputStream(PlatformFilesystem.eaglerRead(path));
|
||||
return new VFileInputStream(getFS().eaglerRead(path));
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
@ -121,7 +162,7 @@ public class VFile2 {
|
||||
}
|
||||
|
||||
public boolean canRead() {
|
||||
return !isRelative() && PlatformFilesystem.eaglerExists(path);
|
||||
return !isRelative() && getFS().eaglerExists(path);
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
@ -160,15 +201,15 @@ public class VFile2 {
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return !isRelative() && PlatformFilesystem.eaglerExists(path);
|
||||
return !isRelative() && getFS().eaglerExists(path);
|
||||
}
|
||||
|
||||
public boolean delete() {
|
||||
return !isRelative() && PlatformFilesystem.eaglerDelete(path);
|
||||
return !isRelative() && getFS().eaglerDelete(path);
|
||||
}
|
||||
|
||||
public boolean renameTo(String p) {
|
||||
if(!isRelative() && PlatformFilesystem.eaglerMove(path, p)) {
|
||||
if(!isRelative() && getFS().eaglerMove(path, p)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -179,7 +220,7 @@ public class VFile2 {
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return isRelative() ? -1 : PlatformFilesystem.eaglerSize(path);
|
||||
return isRelative() ? -1 : getFS().eaglerSize(path);
|
||||
}
|
||||
|
||||
public byte[] getAllBytes() {
|
||||
@ -187,7 +228,7 @@ public class VFile2 {
|
||||
if(!exists()) {
|
||||
return null;
|
||||
}
|
||||
ByteBuffer readBuffer = PlatformFilesystem.eaglerRead(path);
|
||||
ByteBuffer readBuffer = getFS().eaglerRead(path);
|
||||
byte[] copyBuffer = PlatformRuntime.castNativeByteBuffer(readBuffer);
|
||||
if(copyBuffer != null) {
|
||||
return copyBuffer;
|
||||
@ -225,14 +266,14 @@ public class VFile2 {
|
||||
assertNotRelative();
|
||||
ByteBuffer copyBuffer = PlatformRuntime.castPrimitiveByteArray(bytes);
|
||||
if(copyBuffer != null) {
|
||||
PlatformFilesystem.eaglerWrite(path, copyBuffer);
|
||||
getFS().eaglerWrite(path, copyBuffer);
|
||||
return;
|
||||
}
|
||||
copyBuffer = PlatformRuntime.allocateByteBuffer(bytes.length);
|
||||
try {
|
||||
copyBuffer.put(bytes);
|
||||
copyBuffer.flip();
|
||||
PlatformFilesystem.eaglerWrite(path, copyBuffer);
|
||||
getFS().eaglerWrite(path, copyBuffer);
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(copyBuffer);
|
||||
}
|
||||
@ -240,24 +281,30 @@ public class VFile2 {
|
||||
|
||||
public void iterateFiles(VFSIterator2 itr, boolean recursive) {
|
||||
assertNotRelative();
|
||||
PlatformFilesystem.eaglerIterate(path, new VFSFilenameIteratorImpl(itr), recursive);
|
||||
IEaglerFilesystem fs = getFS();
|
||||
fs.eaglerIterate(path, new VFSFilenameIteratorImpl(fs, itr), recursive);
|
||||
}
|
||||
|
||||
public List<String> listFilenames(boolean recursive) {
|
||||
List<String> ret = new ArrayList();
|
||||
PlatformFilesystem.eaglerIterate(path, new VFSListFilenamesIteratorImpl(ret), recursive);
|
||||
List<String> ret = new ArrayList<>();
|
||||
getFS().eaglerIterate(path, new VFSListFilenamesIteratorImpl(ret), recursive);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<VFile2> listFiles(boolean recursive) {
|
||||
List<VFile2> ret = new ArrayList();
|
||||
PlatformFilesystem.eaglerIterate(path, new VFSListFilesIteratorImpl(ret), recursive);
|
||||
List<VFile2> ret = new ArrayList<>();
|
||||
IEaglerFilesystem fs = getFS();
|
||||
fs.eaglerIterate(path, new VFSListFilesIteratorImpl(fs, ret), recursive);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int copyFile(VFile2 src, VFile2 dst) {
|
||||
src.assertNotRelative();
|
||||
dst.assertNotRelative();
|
||||
return PlatformFilesystem.eaglerCopy(src.path, dst.path);
|
||||
IEaglerFilesystem sfs = src.getFS();
|
||||
if(sfs != dst.getFS()) {
|
||||
throw new UnsupportedOperationException("Cannot copy file between filesystems!");
|
||||
}
|
||||
return sfs.eaglerCopy(src.path, dst.path);
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ package net.lax1dude.eaglercraft.v1_8.internal.vfs2;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||
|
||||
@ -41,7 +40,7 @@ class VFileOutputStream extends EaglerOutputStream {
|
||||
copyBuffer.put(buf, 0, count);
|
||||
copyBuffer.flip();
|
||||
try {
|
||||
PlatformFilesystem.eaglerWrite(vfsFile.path, copyBuffer);
|
||||
vfsFile.getFS().eaglerWrite(vfsFile.path, copyBuffer);
|
||||
}catch(Throwable t) {
|
||||
throw new IOException("Could not write stream contents to file!", t);
|
||||
}
|
||||
|
@ -54,10 +54,10 @@ import net.minecraft.world.gen.ChunkProviderSettings;
|
||||
*/
|
||||
public class JSONTypeProvider {
|
||||
|
||||
private static final Map<Class<?>,JSONTypeSerializer<?,?>> serializers = new HashMap();
|
||||
private static final Map<Class<?>,JSONTypeDeserializer<?,?>> deserializers = new HashMap();
|
||||
private static final Map<Class<?>,JSONTypeSerializer<?,?>> serializers = new HashMap<>();
|
||||
private static final Map<Class<?>,JSONTypeDeserializer<?,?>> deserializers = new HashMap<>();
|
||||
|
||||
private static final List<JSONDataParserImpl> parsers = new ArrayList();
|
||||
private static final List<JSONDataParserImpl> parsers = new ArrayList<>();
|
||||
|
||||
public static <J> J serialize(Object object) throws JSONException {
|
||||
JSONTypeSerializer<Object,J> ser = (JSONTypeSerializer<Object,J>) serializers.get(object.getClass());
|
||||
|
@ -30,7 +30,7 @@ public class SoundMapDeserializer implements JSONTypeDeserializer<JSONObject, So
|
||||
|
||||
@Override
|
||||
public SoundMap deserialize(JSONObject json) throws JSONException {
|
||||
Map<String, SoundList> soundsMap = new HashMap();
|
||||
Map<String, SoundList> soundsMap = new HashMap<>();
|
||||
for(String str : json.keySet()) {
|
||||
soundsMap.put(str, JSONTypeProvider.deserialize(json.getJSONObject(str), SoundList.class));
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class LogManager {
|
||||
|
||||
private static final Map<String,Logger> loggerInstances = new HashMap();
|
||||
private static final Map<String,Logger> loggerInstances = new HashMap<>();
|
||||
|
||||
public static final Object logLock = new Object();
|
||||
public static Level logLevel = Level.DEBUG;
|
||||
|
@ -101,7 +101,7 @@ public class Logger {
|
||||
log(Level.FATAL, msg);
|
||||
}
|
||||
|
||||
private static final SimpleDateFormat fmt = EagRuntime.fixDateFormat(new SimpleDateFormat("hh:mm:ss+SSS"));
|
||||
private static final SimpleDateFormat fmt = new SimpleDateFormat("hh:mm:ss+SSS");
|
||||
private static final Date dateInstance = new Date();
|
||||
|
||||
public void log(Level level, String msg) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user