feat: basic implementation of macro system/Bindings
Co-authored-by: alemi <me@alemi.dev>
This commit is contained in:
parent
63cfbaa56c
commit
067b2e537d
8 changed files with 580 additions and 9 deletions
28
build.gradle
28
build.gradle
|
@ -4,13 +4,14 @@ plugins {
|
||||||
alias libs.plugins.forgeGradle
|
alias libs.plugins.forgeGradle
|
||||||
alias libs.plugins.gitVersion
|
alias libs.plugins.gitVersion
|
||||||
alias libs.plugins.checkerFramework
|
alias libs.plugins.checkerFramework
|
||||||
|
alias libs.plugins.shadow
|
||||||
}
|
}
|
||||||
|
|
||||||
version = gitVersion()
|
version = gitVersion()
|
||||||
group = 'ftbsc'
|
group = 'ftbsc'
|
||||||
archivesBaseName = 'bscv'
|
archivesBaseName = 'bscv'
|
||||||
|
|
||||||
def shortVersion = version.split('-')[0].replaceAll(".dirty", "") // necessary when there are no extra commits on tags, and thus no dash
|
def shortVersion = (version as String).split('-')[0].replaceAll(".dirty", "")
|
||||||
|
|
||||||
project.ext {
|
project.ext {
|
||||||
deployJarDo = getProjectProperty("deployJar.do", "false")
|
deployJarDo = getProjectProperty("deployJar.do", "false")
|
||||||
|
@ -61,6 +62,9 @@ dependencies {
|
||||||
implementation libs.lillero
|
implementation libs.lillero
|
||||||
implementation libs.lilleroProcessor
|
implementation libs.lilleroProcessor
|
||||||
implementation libs.autoServiceAnnotations
|
implementation libs.autoServiceAnnotations
|
||||||
|
implementation libs.luaJava
|
||||||
|
implementation libs.luaJit
|
||||||
|
runtimeOnly libs.luaNatives.get().toString() + ":natives-desktop" //lol
|
||||||
annotationProcessor libs.lilleroProcessor
|
annotationProcessor libs.lilleroProcessor
|
||||||
annotationProcessor libs.autoService
|
annotationProcessor libs.autoService
|
||||||
}
|
}
|
||||||
|
@ -69,8 +73,19 @@ compileJava { //mappings for lillero-processor
|
||||||
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/1.16.5.tsrg'
|
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/1.16.5.tsrg'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def simpleFileName = "${jar.archiveBaseName.get()}-${shortVersion}.${jar.archiveExtension.get()}"
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
archiveFileName = "${jar.archiveBaseName.get()}-${shortVersion}.${jar.archiveExtension.get()}"
|
archiveFileName = simpleFileName
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
archiveFileName = simpleFileName
|
||||||
|
dependencies {
|
||||||
|
include(dependency {
|
||||||
|
it.moduleGroup == 'party.iroiro.luajava'
|
||||||
|
})
|
||||||
|
}
|
||||||
manifest {
|
manifest {
|
||||||
attributes([
|
attributes([
|
||||||
"Specification-Title": "bscv",
|
"Specification-Title": "bscv",
|
||||||
|
@ -84,7 +99,14 @@ jar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jar.finalizedBy('reobfJar')
|
reobf {
|
||||||
|
jar {
|
||||||
|
dependsOn shadowJar
|
||||||
|
}
|
||||||
|
shadowJar {
|
||||||
|
dependsOn jar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//copy jar from build/libs to the forge mod folder
|
//copy jar from build/libs to the forge mod folder
|
||||||
tasks.register('deployJar', Copy) {
|
tasks.register('deployJar', Copy) {
|
||||||
|
|
|
@ -7,11 +7,14 @@ autoService = "1.0.1"
|
||||||
lillero = "0.4.1"
|
lillero = "0.4.1"
|
||||||
lilleroProcessor = "0.5.2"
|
lilleroProcessor = "0.5.2"
|
||||||
checkerFramework = "0.6.24"
|
checkerFramework = "0.6.24"
|
||||||
|
shadow = "7.1.2"
|
||||||
|
luaJava = "3.5.0"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" }
|
forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" }
|
||||||
gitVersion = { id = "com.palantir.git-version", version.ref = "gitVersion" }
|
gitVersion = { id = "com.palantir.git-version", version.ref = "gitVersion" }
|
||||||
checkerFramework = { id = "org.checkerframework", version.ref = "checkerFramework" }
|
checkerFramework = { id = "org.checkerframework", version.ref = "checkerFramework" }
|
||||||
|
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
minecraftForge = { group = "net.minecraftforge", name = "forge", version.ref = "forge" }
|
minecraftForge = { group = "net.minecraftforge", name = "forge", version.ref = "forge" }
|
||||||
|
@ -19,3 +22,6 @@ autoService = { group = "com.google.auto.service", name = "auto-service", versio
|
||||||
autoServiceAnnotations = { group = "com.google.auto.service", name = "auto-service-annotations", version.ref = "autoService" }
|
autoServiceAnnotations = { group = "com.google.auto.service", name = "auto-service-annotations", version.ref = "autoService" }
|
||||||
lillero = { group = "ftbsc", name = "lll", version.ref = "lillero" }
|
lillero = { group = "ftbsc", name = "lll", version.ref = "lillero" }
|
||||||
lilleroProcessor = { group = "ftbsc.lll", name = "processor", version.ref = "lilleroProcessor" }
|
lilleroProcessor = { group = "ftbsc.lll", name = "processor", version.ref = "lilleroProcessor" }
|
||||||
|
luaJava = { group = "party.iroiro.luajava", name = "luajava", version.ref = "luaJava" }
|
||||||
|
luaJit = { group = "party.iroiro.luajava", name = "luajit", version.ref = "luaJava" }
|
||||||
|
luaNatives = { group = "party.iroiro.luajava", name = "luajit-platform", version.ref = "luaJava" }
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2011 See AUTHORS file.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
******************************************************************************/
|
||||||
|
package com.badlogic.gdx.utils;
|
||||||
|
|
||||||
|
public class SharedLibraryLoadRuntimeException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 8263101105331379889L;
|
||||||
|
|
||||||
|
public SharedLibraryLoadRuntimeException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SharedLibraryLoadRuntimeException(Throwable t) {
|
||||||
|
super(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SharedLibraryLoadRuntimeException(String message, Throwable t) {
|
||||||
|
super(message, t);
|
||||||
|
}
|
||||||
|
}
|
355
src/main/java/com/badlogic/gdx/utils/SharedLibraryLoader.java
Normal file
355
src/main/java/com/badlogic/gdx/utils/SharedLibraryLoader.java
Normal file
|
@ -0,0 +1,355 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2011 See AUTHORS file.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
package com.badlogic.gdx.utils;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
/** Loads shared libraries from a natives jar file (desktop) or arm folders (Android). For desktop projects, have the natives jar
|
||||||
|
* in the classpath, for Android projects put the shared libraries in the libs/armeabi and libs/armeabi-v7a folders.
|
||||||
|
* @author mzechner
|
||||||
|
* @author Nathan Sweet */
|
||||||
|
public class SharedLibraryLoader {
|
||||||
|
static public boolean isWindows = System.getProperty("os.name").contains("Windows");
|
||||||
|
static public boolean isLinux = System.getProperty("os.name").contains("Linux");
|
||||||
|
static public boolean isMac = System.getProperty("os.name").contains("Mac");
|
||||||
|
static public boolean isIos = false;
|
||||||
|
static public boolean isAndroid = false;
|
||||||
|
static public boolean isARM = System.getProperty("os.arch").startsWith("arm") || System.getProperty("os.arch").startsWith("aarch64");
|
||||||
|
static public boolean is64Bit = System.getProperty("os.arch").contains("64") || System.getProperty("os.arch").startsWith("armv8");
|
||||||
|
|
||||||
|
static {
|
||||||
|
boolean isMOEiOS = System.getProperty("moe.platform.name") != null;
|
||||||
|
String vm = System.getProperty("java.runtime.name");
|
||||||
|
if (vm != null && vm.contains("Android Runtime")) {
|
||||||
|
isAndroid = true;
|
||||||
|
isWindows = false;
|
||||||
|
isLinux = false;
|
||||||
|
isMac = false;
|
||||||
|
is64Bit = false;
|
||||||
|
}
|
||||||
|
if (isMOEiOS || (!isAndroid && !isWindows && !isLinux && !isMac)) {
|
||||||
|
isIos = true;
|
||||||
|
isAndroid = false;
|
||||||
|
isWindows = false;
|
||||||
|
isLinux = false;
|
||||||
|
isMac = false;
|
||||||
|
is64Bit = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static private final HashSet<String> loadedLibraries = new HashSet<>();
|
||||||
|
static private final Random random = new Random();
|
||||||
|
|
||||||
|
private String nativesJar;
|
||||||
|
|
||||||
|
public SharedLibraryLoader () {
|
||||||
|
}
|
||||||
|
|
||||||
|
static String randomUUID () {
|
||||||
|
return new UUID(random.nextLong(), random.nextLong()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fetches the natives from the given natives jar file. Used for testing a shared lib on the fly.
|
||||||
|
* @param nativesJar */
|
||||||
|
public SharedLibraryLoader (String nativesJar) {
|
||||||
|
this.nativesJar = nativesJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a CRC of the remaining bytes in the stream. */
|
||||||
|
public String crc (InputStream input) {
|
||||||
|
if (input == null) throw new IllegalArgumentException("input cannot be null.");
|
||||||
|
CRC32 crc = new CRC32();
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
int length = input.read(buffer);
|
||||||
|
if (length == -1) break;
|
||||||
|
crc.update(buffer, 0, length);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
} finally {
|
||||||
|
closeQuietly(input);
|
||||||
|
}
|
||||||
|
return Long.toString(crc.getValue(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Maps a platform independent library name to a platform dependent name. */
|
||||||
|
public String mapLibraryName (String libraryName) {
|
||||||
|
if (isWindows) return libraryName + (is64Bit ? "64.dll" : ".dll");
|
||||||
|
if (isLinux) return "lib" + libraryName + (isARM ? "arm" : "") + (is64Bit ? "64.so" : ".so");
|
||||||
|
if (isMac) return "lib" + libraryName + (isARM ? "arm" : "") + (is64Bit ? "64.dylib" : ".dylib");
|
||||||
|
return libraryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Loads a shared library for the platform the application is running on.
|
||||||
|
* @param libraryName The platform independent library name. If not contain a prefix (eg lib) or suffix (eg .dll). */
|
||||||
|
public void load (String libraryName) {
|
||||||
|
// in case of iOS, things have been linked statically to the executable, bail out.
|
||||||
|
if (isIos) return;
|
||||||
|
|
||||||
|
synchronized (SharedLibraryLoader.class) {
|
||||||
|
if (isLoaded(libraryName)) return;
|
||||||
|
String platformName = mapLibraryName(libraryName);
|
||||||
|
try {
|
||||||
|
if (isAndroid)
|
||||||
|
System.loadLibrary(platformName);
|
||||||
|
else
|
||||||
|
loadFile(platformName);
|
||||||
|
setLoaded(libraryName);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
throw new SharedLibraryLoadRuntimeException("Couldn't load shared library '" + platformName + "' for target: "
|
||||||
|
+ (isAndroid ? "Android" : (System.getProperty("os.name") + (isARM ? ", ARM" : "") + (is64Bit ? ", 64-bit" : ", 32-bit"))),
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream readFile (String path) {
|
||||||
|
if (nativesJar == null) {
|
||||||
|
InputStream input = SharedLibraryLoader.class.getResourceAsStream("/" + path);
|
||||||
|
if (input == null) throw new SharedLibraryLoadRuntimeException("Unable to read file for extraction: " + path);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from JAR.
|
||||||
|
try {
|
||||||
|
ZipFile file = new ZipFile(nativesJar);
|
||||||
|
ZipEntry entry = file.getEntry(path);
|
||||||
|
if (entry == null) throw new SharedLibraryLoadRuntimeException("Couldn't find '" + path + "' in JAR: " + nativesJar);
|
||||||
|
return file.getInputStream(entry);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new SharedLibraryLoadRuntimeException("Error reading '" + path + "' in JAR: " + nativesJar, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Extracts the specified file to the specified directory if it does not already exist or the CRC does not match. If file
|
||||||
|
* extraction fails and the file exists at java.library.path, that file is returned.
|
||||||
|
* @param sourcePath The file to extract from the classpath or JAR.
|
||||||
|
* @param dirName The name of the subdirectory where the file will be extracted. If null, the file's CRC will be used.
|
||||||
|
* @return The extracted file. */
|
||||||
|
public File extractFile (String sourcePath, String dirName) throws IOException {
|
||||||
|
try {
|
||||||
|
String sourceCrc = crc(readFile(sourcePath));
|
||||||
|
if (dirName == null) dirName = sourceCrc;
|
||||||
|
|
||||||
|
File extractedFile = getExtractedFile(dirName, new File(sourcePath).getName());
|
||||||
|
if (extractedFile == null) {
|
||||||
|
extractedFile = getExtractedFile(randomUUID(), new File(sourcePath).getName());
|
||||||
|
if (extractedFile == null) throw new SharedLibraryLoadRuntimeException(
|
||||||
|
"Unable to find writable path to extract file. Is the user home directory writable?");
|
||||||
|
}
|
||||||
|
return extractFile(sourcePath, sourceCrc, extractedFile);
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
// Fallback to file at java.library.path location, eg for applets.
|
||||||
|
File file = new File(System.getProperty("java.library.path"), sourcePath);
|
||||||
|
if (file.exists()) return file;
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Extracts the specified file into the temp directory if it does not already exist or the CRC does not match. If file
|
||||||
|
* extraction fails and the file exists at java.library.path, that file is returned.
|
||||||
|
* @param sourcePath The file to extract from the classpath or JAR.
|
||||||
|
* @param dir The location where the extracted file will be written. */
|
||||||
|
public void extractFileTo (String sourcePath, File dir) throws IOException {
|
||||||
|
extractFile(sourcePath, crc(readFile(sourcePath)), new File(dir, new File(sourcePath).getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a path to a file that can be written. Tries multiple locations and verifies writing succeeds.
|
||||||
|
* @return null if a writable path could not be found. */
|
||||||
|
private File getExtractedFile (String dirName, String fileName) {
|
||||||
|
// Temp directory with username in path.
|
||||||
|
File idealFile = new File(
|
||||||
|
System.getProperty("java.io.tmpdir") + "/libgdx" + System.getProperty("user.name") + "/" + dirName, fileName);
|
||||||
|
if (canWrite(idealFile)) return idealFile;
|
||||||
|
|
||||||
|
// System provided temp directory.
|
||||||
|
try {
|
||||||
|
File file = File.createTempFile(dirName, null);
|
||||||
|
if (file.delete()) {
|
||||||
|
file = new File(file, fileName);
|
||||||
|
if (canWrite(file)) return file;
|
||||||
|
}
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// User home.
|
||||||
|
File file = new File(System.getProperty("user.home") + "/.libgdx/" + dirName, fileName);
|
||||||
|
if (canWrite(file)) return file;
|
||||||
|
|
||||||
|
// Relative directory.
|
||||||
|
file = new File(".temp/" + dirName, fileName);
|
||||||
|
if (canWrite(file)) return file;
|
||||||
|
|
||||||
|
// We are running in the OS X sandbox.
|
||||||
|
if (System.getenv("APP_SANDBOX_CONTAINER_ID") != null) return idealFile;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the parent directories of the file can be created and the file can be written. */
|
||||||
|
private boolean canWrite (File file) {
|
||||||
|
File parent = file.getParentFile();
|
||||||
|
File testFile;
|
||||||
|
if (file.exists()) {
|
||||||
|
if (!file.canWrite() || !canExecute(file)) return false;
|
||||||
|
// Don't overwrite existing file just to check if we can write to directory.
|
||||||
|
testFile = new File(parent, randomUUID().toString());
|
||||||
|
} else {
|
||||||
|
parent.mkdirs();
|
||||||
|
if (!parent.isDirectory()) return false;
|
||||||
|
testFile = file;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
new FileOutputStream(testFile).close();
|
||||||
|
if (!canExecute(testFile)) return false;
|
||||||
|
return true;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
testFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canExecute (File file) {
|
||||||
|
try {
|
||||||
|
Method canExecute = File.class.getMethod("canExecute");
|
||||||
|
if ((Boolean)canExecute.invoke(file)) return true;
|
||||||
|
|
||||||
|
Method setExecutable = File.class.getMethod("setExecutable", boolean.class, boolean.class);
|
||||||
|
setExecutable.invoke(file, true, false);
|
||||||
|
|
||||||
|
return (Boolean)canExecute.invoke(file);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File extractFile (String sourcePath, String sourceCrc, File extractedFile) throws IOException {
|
||||||
|
String extractedCrc = null;
|
||||||
|
if (extractedFile.exists()) {
|
||||||
|
try {
|
||||||
|
extractedCrc = crc(new FileInputStream(extractedFile));
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If file doesn't exist or the CRC doesn't match, extract it to the temp dir.
|
||||||
|
if (extractedCrc == null || !extractedCrc.equals(sourceCrc)) {
|
||||||
|
InputStream input = null;
|
||||||
|
FileOutputStream output = null;
|
||||||
|
try {
|
||||||
|
input = readFile(sourcePath);
|
||||||
|
extractedFile.getParentFile().mkdirs();
|
||||||
|
output = new FileOutputStream(extractedFile);
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
while (true) {
|
||||||
|
int length = input.read(buffer);
|
||||||
|
if (length == -1) break;
|
||||||
|
output.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new SharedLibraryLoadRuntimeException("Error extracting file: " + sourcePath + "\nTo: " + extractedFile.getAbsolutePath(),
|
||||||
|
ex);
|
||||||
|
} finally {
|
||||||
|
closeQuietly(input);
|
||||||
|
closeQuietly(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return extractedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Extracts the source file and calls System.load. Attemps to extract and load from multiple locations. Throws runtime
|
||||||
|
* exception if all fail. */
|
||||||
|
private void loadFile (String sourcePath) {
|
||||||
|
String sourceCrc = crc(readFile(sourcePath));
|
||||||
|
|
||||||
|
String fileName = new File(sourcePath).getName();
|
||||||
|
|
||||||
|
// Temp directory with username in path.
|
||||||
|
File file = new File(System.getProperty("java.io.tmpdir") + "/libgdx" + System.getProperty("user.name") + "/" + sourceCrc,
|
||||||
|
fileName);
|
||||||
|
Throwable ex = loadFile(sourcePath, sourceCrc, file);
|
||||||
|
if (ex == null) return;
|
||||||
|
|
||||||
|
// System provided temp directory.
|
||||||
|
try {
|
||||||
|
file = File.createTempFile(sourceCrc, null);
|
||||||
|
if (file.delete() && loadFile(sourcePath, sourceCrc, file) == null) return;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// User home.
|
||||||
|
file = new File(System.getProperty("user.home") + "/.libgdx/" + sourceCrc, fileName);
|
||||||
|
if (loadFile(sourcePath, sourceCrc, file) == null) return;
|
||||||
|
|
||||||
|
// Relative directory.
|
||||||
|
file = new File(".temp/" + sourceCrc, fileName);
|
||||||
|
if (loadFile(sourcePath, sourceCrc, file) == null) return;
|
||||||
|
|
||||||
|
// Fallback to java.library.path location, eg for applets.
|
||||||
|
file = new File(System.getProperty("java.library.path"), sourcePath);
|
||||||
|
if (file.exists()) {
|
||||||
|
System.load(file.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new SharedLibraryLoadRuntimeException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return null if the file was extracted and loaded. */
|
||||||
|
private Throwable loadFile (String sourcePath, String sourceCrc, File extractedFile) {
|
||||||
|
try {
|
||||||
|
System.load(extractFile(sourcePath, sourceCrc, extractedFile).getAbsolutePath());
|
||||||
|
return null;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the library as loaded, for when application code wants to handle libary loading itself. */
|
||||||
|
static public synchronized void setLoaded (String libraryName) {
|
||||||
|
loadedLibraries.add(libraryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public synchronized boolean isLoaded (String libraryName) {
|
||||||
|
return loadedLibraries.contains(libraryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeQuietly (Closeable c) {
|
||||||
|
if (c != null) {
|
||||||
|
try {
|
||||||
|
c.close();
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,9 +6,7 @@ import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
|
||||||
import ftbsc.bscv.api.IModule;
|
import ftbsc.bscv.api.IModule;
|
||||||
import ftbsc.bscv.patches.CommandsPatch.CommandsBuiltEvent;
|
import ftbsc.bscv.patches.CommandsPatch.CommandsBuiltEvent;
|
||||||
import ftbsc.bscv.system.Friends;
|
import ftbsc.bscv.system.*;
|
||||||
import ftbsc.bscv.system.ModManager;
|
|
||||||
import ftbsc.bscv.system.Ruler;
|
|
||||||
import net.minecraft.client.gui.screen.IngameMenuScreen;
|
import net.minecraft.client.gui.screen.IngameMenuScreen;
|
||||||
import net.minecraft.client.gui.widget.button.Button;
|
import net.minecraft.client.gui.widget.button.Button;
|
||||||
import net.minecraft.command.CommandSource;
|
import net.minecraft.command.CommandSource;
|
||||||
|
@ -27,6 +25,7 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
@Mod("bscv")
|
@Mod("bscv")
|
||||||
public class Boscovicino implements ICommons {
|
public class Boscovicino implements ICommons {
|
||||||
|
@ -34,7 +33,7 @@ public class Boscovicino implements ICommons {
|
||||||
|
|
||||||
public static final Logger LOGGER = LogManager.getLogger();
|
public static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
public static ModManager modManager; //todo this should not be static
|
public static ModManager modManager; //todo rename
|
||||||
|
|
||||||
private final CommandDispatcher<CommandSource> dispatcher = new CommandDispatcher<>();
|
private final CommandDispatcher<CommandSource> dispatcher = new CommandDispatcher<>();
|
||||||
|
|
||||||
|
@ -46,7 +45,10 @@ public class Boscovicino implements ICommons {
|
||||||
@SuppressWarnings("unused") // it just needs to exist to be used by player
|
@SuppressWarnings("unused") // it just needs to exist to be used by player
|
||||||
private static Ruler ruler;
|
private static Ruler ruler;
|
||||||
|
|
||||||
public Boscovicino() {
|
public static Bindings bindings;
|
||||||
|
public static Macros macros;
|
||||||
|
|
||||||
|
public Boscovicino() throws IOException {
|
||||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetupComplete);
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetupComplete);
|
||||||
|
|
||||||
ForgeConfigSpec.Builder cfg = new ForgeConfigSpec.Builder();
|
ForgeConfigSpec.Builder cfg = new ForgeConfigSpec.Builder();
|
||||||
|
@ -59,6 +61,10 @@ public class Boscovicino implements ICommons {
|
||||||
|
|
||||||
Boscovicino.ruler = new Ruler();
|
Boscovicino.ruler = new Ruler();
|
||||||
|
|
||||||
|
ForgeConfigSpec.Builder bindingSpec = new ForgeConfigSpec.Builder();
|
||||||
|
Boscovicino.bindings = new Bindings(bindingSpec);
|
||||||
|
Boscovicino.macros = new Macros();
|
||||||
|
|
||||||
Boscovicino.spec = cfg.build();
|
Boscovicino.spec = cfg.build();
|
||||||
|
|
||||||
ForgeConfigSpec.Builder friendSpec = new ForgeConfigSpec.Builder();
|
ForgeConfigSpec.Builder friendSpec = new ForgeConfigSpec.Builder();
|
||||||
|
@ -67,6 +73,7 @@ public class Boscovicino implements ICommons {
|
||||||
// register config handler
|
// register config handler
|
||||||
ModLoadingContext.get().registerConfig(Type.CLIENT, spec, "bscv.toml");
|
ModLoadingContext.get().registerConfig(Type.CLIENT, spec, "bscv.toml");
|
||||||
ModLoadingContext.get().registerConfig(Type.CLIENT, friendSpec.build(), "friends.toml");
|
ModLoadingContext.get().registerConfig(Type.CLIENT, friendSpec.build(), "friends.toml");
|
||||||
|
ModLoadingContext.get().registerConfig(Type.CLIENT, bindingSpec.build(), "bindings.toml");
|
||||||
|
|
||||||
// Register ourselves for server and other game events we are interested in
|
// Register ourselves for server and other game events we are interested in
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
|
89
src/main/java/ftbsc/bscv/system/Bindings.java
Normal file
89
src/main/java/ftbsc/bscv/system/Bindings.java
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package ftbsc.bscv.system;
|
||||||
|
|
||||||
|
import ftbsc.bscv.Boscovicino;
|
||||||
|
import ftbsc.bscv.api.IModule;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.settings.KeyBinding;
|
||||||
|
import net.minecraft.client.util.InputMappings;
|
||||||
|
import net.minecraftforge.client.event.InputEvent;
|
||||||
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Bindings {
|
||||||
|
public static final int UNBOUND = InputMappings.UNKNOWN.getValue();
|
||||||
|
|
||||||
|
private final HashMap<KeyBinding, Runnable> executorMap;
|
||||||
|
|
||||||
|
private ForgeConfigSpec.ConfigValue<?> store;
|
||||||
|
|
||||||
|
public Bindings(ForgeConfigSpec.Builder spec) {
|
||||||
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
this.executorMap = new HashMap<>();
|
||||||
|
this.store = spec
|
||||||
|
//.comment("actual friend list")
|
||||||
|
.define("lol", () -> null, (u) -> {
|
||||||
|
System.out.println(u.getClass().getName());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyBinding registerBinding(String name, int key, IModule module) {
|
||||||
|
KeyBinding kb = this.createBinding(name, key);
|
||||||
|
this.executorMap.put(kb, module::toggle);
|
||||||
|
return kb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyBinding registerBinding(String name, int key, String macroFileName) {
|
||||||
|
KeyBinding kb = this.createBinding(name, key);
|
||||||
|
this.executorMap.put(kb, () -> {
|
||||||
|
Boscovicino.macros.execute(macroFileName);
|
||||||
|
});
|
||||||
|
return kb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyBinding createBinding(String name, int key) {
|
||||||
|
KeyBinding kb = new KeyBinding(getBindName(name), UNBOUND, getCategory());
|
||||||
|
InputMappings.Input in = 0 <= key && key <= 7
|
||||||
|
? InputMappings.Type.MOUSE.getOrCreate(key)
|
||||||
|
: InputMappings.Type.KEYSYM.getOrCreate(key);
|
||||||
|
kb.setKey(in);
|
||||||
|
ClientRegistry.registerKeyBinding(kb);
|
||||||
|
return kb;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onKeyPress(InputEvent.KeyInputEvent event) {
|
||||||
|
this.onKeyPress(event.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onKeyPress(InputEvent.MouseInputEvent event) {
|
||||||
|
this.onKeyPress(event.getButton());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO on keybind change event
|
||||||
|
private void onKeyPress(int key) {
|
||||||
|
long windowId = Minecraft.getInstance().getWindow().getWindow();
|
||||||
|
for(KeyBinding kb : this.executorMap.keySet()) {
|
||||||
|
if(kb.getKey().getValue() == key) {
|
||||||
|
if(InputMappings.isKeyDown(windowId, key)) this.executorMap.get(kb).run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getBindName(String name) {
|
||||||
|
return String.format("key.%s.%s", Boscovicino.MOD_ID, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getCategory() {
|
||||||
|
return String.format("key.category.%s", Boscovicino.MOD_ID);
|
||||||
|
}
|
||||||
|
}
|
50
src/main/java/ftbsc/bscv/system/Macros.java
Normal file
50
src/main/java/ftbsc/bscv/system/Macros.java
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package ftbsc.bscv.system;
|
||||||
|
|
||||||
|
import ftbsc.bscv.Boscovicino;
|
||||||
|
import party.iroiro.luajava.Lua;
|
||||||
|
import party.iroiro.luajava.luajit.LuaJit;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.DirectoryStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class Macros {
|
||||||
|
private final Lua lua;
|
||||||
|
private final HashMap<String, String> macroCache;
|
||||||
|
|
||||||
|
public Macros() throws IOException {
|
||||||
|
this.lua = new LuaJit();
|
||||||
|
this.lua.pushJavaClass(Boscovicino.class); //TODO use instance
|
||||||
|
this.lua.setGlobal("BSCV");
|
||||||
|
this.macroCache = new HashMap<>();
|
||||||
|
|
||||||
|
// load macros
|
||||||
|
Path path = Paths.get("macros/");
|
||||||
|
if(!Files.isDirectory(path)) {
|
||||||
|
Files.createDirectories(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO lazy load setting
|
||||||
|
try(DirectoryStream<Path> stream = Files.newDirectoryStream(path, (p) -> p.toFile().isFile())) {
|
||||||
|
for(Path macro : stream) {
|
||||||
|
String name = macro.getFileName().toString();
|
||||||
|
if(name.endsWith(".lua")) {
|
||||||
|
String code = String.join("\n", Files.readAllLines(macro));
|
||||||
|
this.macroCache.put(name, code);
|
||||||
|
Boscovicino.bindings.registerBinding(name, Bindings.UNBOUND, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean execute(String macroFilePath) {
|
||||||
|
String code = this.macroCache.get(macroFilePath);
|
||||||
|
if(code == null) return false;
|
||||||
|
|
||||||
|
this.lua.execute(code);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,16 @@ public class ModManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public IModule get(String name) {
|
||||||
|
for (IModule m : this.mods) {
|
||||||
|
if (m.getName().equals(name)) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void load() {
|
public void load() {
|
||||||
for (ILoadable module : ServiceLoader.load(ILoadable.class)) {
|
for (ILoadable module : ServiceLoader.load(ILoadable.class)) {
|
||||||
if(module instanceof IModule) {
|
if(module instanceof IModule) {
|
||||||
|
|
Loading…
Reference in a new issue