diff --git a/loader/legacy/pom.xml b/loader/legacy/pom.xml
new file mode 100644
index 00000000..83e1c500
--- /dev/null
+++ b/loader/legacy/pom.xml
@@ -0,0 +1,156 @@
+
+
+ 4.0.0
+
+ com.code-disaster.steamworks4j
+ steamworks4j-legacy
+ 1.10.0-SNAPSHOT
+
+ jar
+
+ Steam API Java Wrapper - Legacy library loader
+ Java wrapper to access the Steamworks API.
+ http://github.com/code-disaster/steamworks4j
+
+
+ http://github.com/code-disaster/steamworks4j/issues
+
+
+
+
+ MIT License
+ http://www.opensource.org/licenses/mit-license.php
+
+
+
+
+
+ Daniel Ludwig
+ codi@code-disaster.com
+ +1
+
+
+
+
+ scm:git:https://github.com/code-disaster/steamworks4j.git
+ scm:git:https://github.com/code-disaster/steamworks4j.git
+ http://github.com/code-disaster/steamworks4j
+
+
+
+
+ release
+
+
+ ossrh
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 3.0.1
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+
+
+
+ snapshot
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+
+
+ java-8-api
+
+ [9,)
+
+
+ 8
+
+
+
+
+
+ UTF-8
+ UTF-8
+
+
+
+
+ com.code-disaster.steamworks4j
+ steamworks4j
+ 1.10.0-SNAPSHOT
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+
+
+
+ maven-compiler-plugin
+ 3.11.0
+
+
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.3.0
+
+ true
+
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.5.0
+
+
+ attach-javadocs
+
+ jar
+
+
+ none
+
+
+
+
+
+
+
diff --git a/loader/legacy/src/main/java/com/codedisaster/steamworks/SteamLibraryLoaderLegacy.java b/loader/legacy/src/main/java/com/codedisaster/steamworks/SteamLibraryLoaderLegacy.java
new file mode 100644
index 00000000..21821ff7
--- /dev/null
+++ b/loader/legacy/src/main/java/com/codedisaster/steamworks/SteamLibraryLoaderLegacy.java
@@ -0,0 +1,273 @@
+package com.codedisaster.steamworks;
+
+import java.io.*;
+import java.util.UUID;
+
+@Deprecated
+public class SteamLibraryLoaderLegacy implements SteamLibraryLoader {
+
+ enum PLATFORM {
+ Windows,
+ Linux,
+ MacOS
+ }
+
+ private String libraryPath;
+
+ private static final PLATFORM OS;
+ private static final boolean IS_64_BIT;
+
+ private static final String SHARED_LIBRARY_EXTRACT_DIRECTORY = System.getProperty(
+ "com.codedisaster.steamworks.SharedLibraryExtractDirectory", "steamworks4j");
+
+ private static final String SHARED_LIBRARY_EXTRACT_PATH = System.getProperty(
+ "com.codedisaster.steamworks.SharedLibraryExtractPath", null);
+
+ private static final String SDK_REDISTRIBUTABLE_BIN_PATH = System.getProperty(
+ "com.codedisaster.steamworks.SDKRedistributableBinPath", "sdk/redistributable_bin");
+
+ private static final String SDK_LIBRARY_PATH = System.getProperty(
+ "com.codedisaster.steamworks.SDKLibraryPath", "sdk/public/steam/lib");
+
+ static final boolean DEBUG = Boolean.parseBoolean(System.getProperty(
+ "com.codedisaster.steamworks.Debug", "false"));
+
+ static {
+ String osName = System.getProperty("os.name");
+ String osArch = System.getProperty("os.arch");
+
+ if (osName.contains("Windows")) {
+ OS = PLATFORM.Windows;
+ } else if (osName.contains("Linux")) {
+ OS = PLATFORM.Linux;
+ } else if (osName.contains("Mac")) {
+ OS = PLATFORM.MacOS;
+ } else {
+ throw new RuntimeException("Unknown host architecture: " + osName + ", " + osArch);
+ }
+
+ IS_64_BIT = osArch.equals("amd64") || osArch.equals("x86_64");
+ }
+
+ private static String getPlatformLibName(String libName) {
+ switch (OS) {
+ case Windows:
+ return libName + (IS_64_BIT ? "64" : "") + ".dll";
+ case Linux:
+ return "lib" + libName + ".so";
+ case MacOS:
+ return "lib" + libName + ".dylib";
+ }
+
+ throw new RuntimeException("Unknown host architecture");
+ }
+
+ static String getSdkRedistributableBinPath() {
+ File path;
+ switch (OS) {
+ case Windows:
+ path = new File(SDK_REDISTRIBUTABLE_BIN_PATH, IS_64_BIT ? "win64" : "");
+ break;
+ case Linux:
+ path = new File(SDK_REDISTRIBUTABLE_BIN_PATH, "linux64");
+ break;
+ case MacOS:
+ path = new File(SDK_REDISTRIBUTABLE_BIN_PATH, "osx");
+ break;
+ default:
+ return null;
+ }
+
+ return path.exists() ? path.getPath() : null;
+ }
+
+ static String getSdkLibraryPath() {
+ File path;
+ switch (OS) {
+ case Windows:
+ path = new File(SDK_LIBRARY_PATH, IS_64_BIT ? "win64" : "win32");
+ break;
+ case Linux:
+ path = new File(SDK_LIBRARY_PATH, "linux64");
+ break;
+ case MacOS:
+ path = new File(SDK_LIBRARY_PATH, "osx");
+ break;
+ default:
+ return null;
+ }
+
+ return path.exists() ? path.getPath() : null;
+ }
+
+ @Override
+ public void setLibraryPath(String libraryPath) {
+ this.libraryPath = libraryPath;
+ }
+
+ @Override
+ public boolean loadLibrary(String libraryName) {
+ try {
+ String librarySystemName = getPlatformLibName(libraryName);
+
+ File librarySystemPath = discoverExtractLocation(
+ SHARED_LIBRARY_EXTRACT_DIRECTORY + "/" + Version.getVersion(), librarySystemName);
+
+ if (libraryPath == null) {
+ // extract library from resource
+ extractLibrary(librarySystemPath, librarySystemName);
+ } else {
+ // read library from given path
+ File librarySourcePath = new File(libraryPath, librarySystemName);
+
+ if (OS != PLATFORM.Windows) {
+ // on MacOS & Linux, "extract" (copy) from source location
+ extractLibrary(librarySystemPath, librarySourcePath);
+ } else {
+ // on Windows, load the library from the source location
+ librarySystemPath = librarySourcePath;
+ }
+ }
+
+ String absolutePath = librarySystemPath.getCanonicalPath();
+ System.load(absolutePath);
+ } catch (IOException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private static void extractLibrary(File librarySystemPath, String librarySystemName) throws IOException {
+ extractLibrary(librarySystemPath,
+ SteamLibraryLoaderLegacy.class.getResourceAsStream("/" + librarySystemName));
+ }
+
+ private static void extractLibrary(File librarySystemPath, File librarySourcePath) throws IOException {
+ extractLibrary(librarySystemPath, new FileInputStream(librarySourcePath));
+ }
+
+ private static void extractLibrary(File librarySystemPath, InputStream input) throws IOException {
+ if (input != null) {
+ try (FileOutputStream output = new FileOutputStream(librarySystemPath)) {
+ byte[] buffer = new byte[4096];
+ while (true) {
+ int length = input.read(buffer);
+ if (length == -1) break;
+ output.write(buffer, 0, length);
+ }
+ } catch (IOException e) {
+ /*
+ Extracting the library may fail, for example because 'nativeFile' already exists and is in
+ use by another process. In this case, we fail silently and just try to load the existing file.
+ */
+ if (!librarySystemPath.exists()) {
+ throw e;
+ }
+ } finally {
+ input.close();
+ }
+ } else {
+ throw new IOException("Failed to read input stream for " + librarySystemPath.getCanonicalPath());
+ }
+ }
+
+ private static File discoverExtractLocation(String folderName, String fileName) throws IOException {
+
+ File path;
+
+ // system property
+
+ if (SHARED_LIBRARY_EXTRACT_PATH != null) {
+ path = new File(SHARED_LIBRARY_EXTRACT_PATH, fileName);
+ if (canWrite(path)) {
+ return path;
+ }
+ }
+
+ // Java tmpdir
+
+ path = new File(System.getProperty("java.io.tmpdir") + "/" + folderName, fileName);
+ if (canWrite(path)) {
+ return path;
+ }
+
+ // NIO temp file
+
+ try {
+ File file = File.createTempFile(folderName, null);
+ if (file.delete()) {
+ // uses temp file path as destination folder
+ path = new File(file, fileName);
+ if (canWrite(path)) {
+ return path;
+ }
+ }
+ } catch (IOException ignored) {
+
+ }
+
+ // user home
+
+ path = new File(System.getProperty("user.home") + "/." + folderName, fileName);
+ if (canWrite(path)) {
+ return path;
+ }
+
+ // working directory
+
+ path = new File(".tmp/" + folderName, fileName);
+ if (canWrite(path)) {
+ return path;
+ }
+
+ throw new IOException("No suitable extraction path found");
+ }
+
+ private static boolean canWrite(File file) {
+
+ File folder = file.getParentFile();
+
+ if (file.exists()) {
+ if (!file.canWrite() || !canExecute(file)) {
+ return false;
+ }
+ } else {
+ if (!folder.exists()) {
+ if (!folder.mkdirs()) {
+ return false;
+ }
+ }
+ if (!folder.isDirectory()) {
+ return false;
+ }
+ }
+
+ File testFile = new File(folder, UUID.randomUUID().toString());
+
+ try {
+ new FileOutputStream(testFile).close();
+ return canExecute(testFile);
+ } catch (IOException e) {
+ return false;
+ } finally {
+ testFile.delete();
+ }
+ }
+
+ private static boolean canExecute(File file) {
+
+ try {
+ if (file.canExecute()) {
+ return true;
+ }
+
+ if (file.setExecutable(true)) {
+ return file.canExecute();
+ }
+ } catch (Exception ignored) {
+
+ }
+
+ return false;
+ }
+}
diff --git a/pom.xml b/pom.xml
index 665a56d8..6b17ff8e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,7 @@
jnigen
loader/gdx
loader/lwjgl3
+ loader/legacy
server
tests
diff --git a/tests/pom.xml b/tests/pom.xml
index 86582b1c..83ecf6d5 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -49,6 +49,11 @@
steamworks4j-lwjgl3
1.10.0-SNAPSHOT
+
+ com.code-disaster.steamworks4j
+ steamworks4j-legacy
+ 1.10.0-SNAPSHOT
+
com.code-disaster.steamworks4j
steamworks4j-server
diff --git a/tests/src/main/java/com/codedisaster/steamworks/test/SteamTestApp.java b/tests/src/main/java/com/codedisaster/steamworks/test/SteamTestApp.java
index 6e6872ca..b6dd5b05 100644
--- a/tests/src/main/java/com/codedisaster/steamworks/test/SteamTestApp.java
+++ b/tests/src/main/java/com/codedisaster/steamworks/test/SteamTestApp.java
@@ -263,6 +263,10 @@ private static SteamLibraryLoader createLibraryLoader(String[] arguments) {
loader = new SteamLibraryLoaderGdx();
break;
}
+ if (arg.equals("--legacy")) {
+ loader = new SteamLibraryLoaderLegacy();
+ break;
+ }
}
if (loader == null) {