forked from Clones/Controlify
SDL2 natives are now downloaded through maven
This commit is contained in:
@ -11,11 +11,12 @@ plugins {
|
|||||||
alias(libs.plugins.github.release)
|
alias(libs.plugins.github.release)
|
||||||
alias(libs.plugins.machete)
|
alias(libs.plugins.machete)
|
||||||
alias(libs.plugins.grgit)
|
alias(libs.plugins.grgit)
|
||||||
|
alias(libs.plugins.blossom)
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "dev.isxander"
|
group = "dev.isxander"
|
||||||
version = "1.1.0-beta.2+1.19.4"
|
version = "1.1.0-beta.3+1.19.4"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
@ -112,6 +113,11 @@ dependencies {
|
|||||||
"testmodImplementation"(sourceSets.main.get().output)
|
"testmodImplementation"(sourceSets.main.get().output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blossom {
|
||||||
|
val sdl2ManagerClass = "src/main/java/dev/isxander/controlify/controller/sdl2/SDL2NativesManager.java"
|
||||||
|
replaceToken("<SDL2_VERSION>", libs.versions.sdl2.jni.get(), sdl2ManagerClass)
|
||||||
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
processResources {
|
processResources {
|
||||||
val modId: String by project
|
val modId: String by project
|
||||||
|
@ -6,6 +6,7 @@ cursegradle = "2.+"
|
|||||||
github_release = "2.+"
|
github_release = "2.+"
|
||||||
machete = "1.+"
|
machete = "1.+"
|
||||||
grgit = "5.0.+"
|
grgit = "5.0.+"
|
||||||
|
blossom = "1.3.+"
|
||||||
|
|
||||||
minecraft = "1.19.4"
|
minecraft = "1.19.4"
|
||||||
quilt_mappings = "10"
|
quilt_mappings = "10"
|
||||||
@ -19,7 +20,7 @@ quilt_json5 = "1.0.3"
|
|||||||
sodium = "mc1.19.4-0.4.10"
|
sodium = "mc1.19.4-0.4.10"
|
||||||
iris = "1.5.2+1.19.4"
|
iris = "1.5.2+1.19.4"
|
||||||
immediately_fast = "1.1.10+1.19.4"
|
immediately_fast = "1.1.10+1.19.4"
|
||||||
sdl2_jni = "1.0.0"
|
sdl2_jni = "2.26.4-4"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
||||||
@ -47,3 +48,4 @@ cursegradle = { id = "me.hypherionmc.cursegradle", version.ref = "cursegradle" }
|
|||||||
github_release = { id = "com.github.breadmoirai.github-release", version.ref = "github_release" }
|
github_release = { id = "com.github.breadmoirai.github-release", version.ref = "github_release" }
|
||||||
machete = { id = "io.github.p03w.machete", version.ref = "machete" }
|
machete = { id = "io.github.p03w.machete", version.ref = "machete" }
|
||||||
grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }
|
grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }
|
||||||
|
blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
|
||||||
|
@ -6,7 +6,6 @@ import net.minecraft.Util;
|
|||||||
import org.libsdl.SDL;
|
import org.libsdl.SDL;
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
@ -14,19 +13,19 @@ import java.nio.channels.ReadableByteChannel;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
import static org.libsdl.SDL_Hints.*;
|
||||||
|
|
||||||
public class SDL2NativesManager {
|
public class SDL2NativesManager {
|
||||||
private static final Path NATIVES_FOLDER = FabricLoader.getInstance().getGameDir().resolve("controlify-natives");
|
private static final String SDL2_VERSION = "<SDL2_VERSION>";
|
||||||
private static final Map<Target, String> NATIVE_LIBRARIES = Map.of(
|
private static final Map<Target, String> NATIVE_LIBRARIES = Map.of(
|
||||||
new Target(Util.OS.WINDOWS, true), "windows64/sdl2gdx64.dll",
|
new Target(Util.OS.WINDOWS, true), "windows64.dll",
|
||||||
new Target(Util.OS.WINDOWS, false), "windows32/sdl2gdx.dll",
|
new Target(Util.OS.WINDOWS, false), "window32.dll",
|
||||||
new Target(Util.OS.LINUX, true), "linux64/libsdl2gdx64.so",
|
new Target(Util.OS.LINUX, true), "linux64.so"
|
||||||
new Target(Util.OS.OSX, true), "macosx64/libsdl2gdx64.dylib"
|
//new Target(Util.OS.OSX, true), "mac64.dylib"
|
||||||
);
|
);
|
||||||
private static final String NATIVE_LIBRARY_URL = "https://raw.githubusercontent.com/isXander/sdl2-jni/master/libs/";
|
private static final String NATIVE_LIBRARY_URL = "https://maven.isxander.dev/releases/dev/isxander/sdl2-jni-natives/%s/".formatted(SDL2_VERSION);
|
||||||
|
|
||||||
private static Path osNativePath;
|
|
||||||
private static boolean loaded = false;
|
private static boolean loaded = false;
|
||||||
|
|
||||||
public static void initialise() {
|
public static void initialise() {
|
||||||
@ -34,31 +33,46 @@ public class SDL2NativesManager {
|
|||||||
|
|
||||||
Controlify.LOGGER.info("Initialising SDL2 native library");
|
Controlify.LOGGER.info("Initialising SDL2 native library");
|
||||||
|
|
||||||
osNativePath = getNativesPathForOS().orElseGet(() -> {
|
if (!Target.CURRENT.hasNativeLibrary()) {
|
||||||
Controlify.LOGGER.warn("No native library found for SDL2");
|
Controlify.LOGGER.warn("SDL2 native library not available for OS: " + Target.CURRENT);
|
||||||
return null;
|
return;
|
||||||
});
|
|
||||||
|
|
||||||
if (osNativePath == null) return;
|
|
||||||
|
|
||||||
if (!loadCachedLibrary()) {
|
|
||||||
downloadLibrary();
|
|
||||||
|
|
||||||
if (!loadCachedLibrary()) {
|
|
||||||
Controlify.LOGGER.warn("Failed to download and load SDL2 native library");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Path localLibraryPath = Target.CURRENT.getLocalNativePath();
|
||||||
|
if (Files.notExists(localLibraryPath)) {
|
||||||
|
Controlify.LOGGER.info("Downloading SDL2 native library: " + Target.CURRENT.getArtifactName());
|
||||||
|
downloadLibrary(localLibraryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SDL.load(localLibraryPath);
|
||||||
|
|
||||||
|
startSDL2();
|
||||||
|
|
||||||
|
loaded = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Controlify.LOGGER.error("Failed to load SDL2 native library", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startSDL2() {
|
private static void startSDL2() {
|
||||||
SDL.SDL_SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1");
|
// we have no windows, so all events are background events
|
||||||
SDL.SDL_SetHint("SDL_ACCELEROMETER_AS_JOYSTICK", "0");
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||||
SDL.SDL_SetHint("SDL_MAC_BACKGROUND_APP", "1");
|
// accelerometer as joystick is not good UX. unexpected
|
||||||
SDL.SDL_SetHint("SDL_XINPUT_ENABLED", "1");
|
SDL.SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
|
||||||
SDL.SDL_SetHint("SDL_JOYSTICK_RAWINPUT", "0");
|
// see first hint
|
||||||
|
SDL.SDL_SetHint(SDL_HINT_MAC_BACKGROUND_APP, "1");
|
||||||
|
// raw input requires controller correlation, which is impossible
|
||||||
|
// without calling JoystickUpdate, which we don't do.
|
||||||
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
|
||||||
|
// better rumble
|
||||||
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
|
||||||
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
|
||||||
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1");
|
||||||
|
|
||||||
int joystickSubsystem = 0x00000200; // implies event subsystem
|
int joystickSubsystem = 0x00000200; // implies event subsystem
|
||||||
if (SDL.SDL_Init(joystickSubsystem) != 0) {
|
int gameControllerSubsystem = 0x00002000; // implies event subsystem
|
||||||
|
if (SDL.SDL_Init(joystickSubsystem | gameControllerSubsystem) != 0) {
|
||||||
Controlify.LOGGER.error("Failed to initialise SDL2: " + SDL.SDL_GetError());
|
Controlify.LOGGER.error("Failed to initialise SDL2: " + SDL.SDL_GetError());
|
||||||
throw new RuntimeException("Failed to initialise SDL2: " + SDL.SDL_GetError());
|
throw new RuntimeException("Failed to initialise SDL2: " + SDL.SDL_GetError());
|
||||||
}
|
}
|
||||||
@ -66,43 +80,24 @@ public class SDL2NativesManager {
|
|||||||
Controlify.LOGGER.info("Initialised SDL2");
|
Controlify.LOGGER.info("Initialised SDL2");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean loadCachedLibrary() {
|
private static boolean downloadLibrary(Path path) {
|
||||||
if (!Files.exists(osNativePath)) return false;
|
|
||||||
|
|
||||||
Controlify.LOGGER.info("Loading SDL2 native library from " + osNativePath);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SDL.load(osNativePath);
|
Files.deleteIfExists(path);
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
startSDL2();
|
Files.createFile(path);
|
||||||
|
} catch (Exception e) {
|
||||||
loaded = true;
|
|
||||||
return true;
|
|
||||||
} catch (UnsatisfiedLinkError e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean downloadLibrary() {
|
try(FileOutputStream fileOutputStream = new FileOutputStream(path.toFile())) {
|
||||||
Controlify.LOGGER.info("Downloading SDL2 native library");
|
String url = NATIVE_LIBRARY_URL + Target.CURRENT.getArtifactName();
|
||||||
|
URL downloadUrl = new URL(url);
|
||||||
try {
|
ReadableByteChannel readableByteChannel = Channels.newChannel(downloadUrl.openStream());
|
||||||
Files.deleteIfExists(osNativePath);
|
|
||||||
Files.createDirectories(osNativePath.getParent());
|
|
||||||
Files.createFile(osNativePath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try(FileOutputStream fileOutputStream = new FileOutputStream(osNativePath.toFile())) {
|
|
||||||
String downloadUrl = NATIVE_LIBRARY_URL + NATIVE_LIBRARIES.get(getNativeLibraryType());
|
|
||||||
URL url = new URL(downloadUrl);
|
|
||||||
ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
|
|
||||||
FileChannel fileChannel = fileOutputStream.getChannel();
|
FileChannel fileChannel = fileOutputStream.getChannel();
|
||||||
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
|
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
|
||||||
Controlify.LOGGER.info("Downloaded SDL2 native library from " + downloadUrl);
|
Controlify.LOGGER.info("Downloaded SDL2 native library from " + downloadUrl);
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -110,28 +105,31 @@ public class SDL2NativesManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Target getNativeLibraryType() {
|
|
||||||
Util.OS os = Util.getPlatform();
|
|
||||||
boolean is64bit = System.getProperty("os.arch").contains("64");
|
|
||||||
|
|
||||||
return new Target(os, is64bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<Path> getNativesPathForOS() {
|
|
||||||
String path = NATIVE_LIBRARIES.get(getNativeLibraryType());
|
|
||||||
|
|
||||||
if (path == null) {
|
|
||||||
Controlify.LOGGER.warn("No native library found for SDL " + getNativeLibraryType());
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.of(NATIVES_FOLDER.resolve(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLoaded() {
|
public static boolean isLoaded() {
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private record Target(Util.OS os, boolean is64Bit) {
|
private record Target(Util.OS os, boolean is64Bit) {
|
||||||
|
public static final Target CURRENT = Util.make(() -> {
|
||||||
|
Util.OS os = Util.getPlatform();
|
||||||
|
boolean is64bit = System.getProperty("os.arch").contains("64");
|
||||||
|
|
||||||
|
return new Target(os, is64bit);
|
||||||
|
});
|
||||||
|
|
||||||
|
public boolean hasNativeLibrary() {
|
||||||
|
return NATIVE_LIBRARIES.containsKey(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getArtifactName() {
|
||||||
|
String suffix = NATIVE_LIBRARIES.get(Target.CURRENT);
|
||||||
|
return "sdl2-jni-natives-" + SDL2_VERSION + "-" + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getLocalNativePath() {
|
||||||
|
return FabricLoader.getInstance().getGameDir()
|
||||||
|
.resolve("controlify-natives")
|
||||||
|
.resolve(getArtifactName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user