1
0
forked from Clones/Controlify

SDL2 natives are now downloaded through maven

This commit is contained in:
isXander
2023-04-11 10:31:43 +01:00
parent 27bf02ee30
commit 021e2daa46
3 changed files with 80 additions and 74 deletions

View File

@ -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

View File

@ -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" }

View File

@ -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());
}
} }
} }