code-disaster / steamworks4j

A thin Java wrapper to access the Steamworks API
https://code-disaster.github.io/steamworks4j/
MIT License
468 stars 64 forks source link

SteamAPI.loadLibraries fails with UnsatisfiedLinkError when unicode characters are in the windows username #115

Open 00-Evan opened 2 years ago

00-Evan commented 2 years ago

I recently released my game on Steam, using libGDX 1.10.0 and Steamworks4j 1.9.0.

It has largely been working well, but a few chinese/korean users have been getting crashes due to the game being unable to load natives, here is one such crash message that was reported to me:

image

The common point among all these users are korean or chinese glyphs in their windows user directory (shown above as question marks in my error popup).

Upon further inspection, I found that steamworks4j seems to load natives in a similar way to libGDX, but no such errors were occurring when libGDX's natives were loaded prior to steamwork4j, so I have worked around the error for now by making the following change:

SteamAPI.loadLibraries();

to

new SharedLibraryLoader().load("steam_api"); new SharedLibraryLoader().load("steamworks4j"); SteamAPI.skipLoadLibraries();

This workaround fixes the errors for the users who have reported it. I'm not sure exactly what, but SharedLibraryLoader.loadFile seems to be doing something that SteamSharedLibraryLoader.discoverExtractLocation isn't.

00-Evan commented 2 years ago

As a small addendum, using libGDX's SharedLibraryLoader does not work so easily on linux/mac due to differing native names. I've reverted back to SteamAPI.loadLibraries() on those platforms, as no issues were reported there in the first place.

code-disaster commented 2 years ago

This is a long-time error with System.load(), as far as I know. I don't know if anyone (LWJGL3, possibly?) was able to work around that. For the Windows build of Pathway I "fixed" this by shipping DLLs in a bin/ folder right next to the executable, avoiding the "extract and load", and using LWJGL's org.lwjgl.librarypath and Library.load() instead.

About the names libGDX expects: one can work around that by extending SharedLibraryLoader and overriding/modifying mapLibraryName().

00-Evan commented 2 years ago

Hm, I couldn't say exactly how libGDX works around this, all I know is that these users did report the game working properly after I switched to libGDX's natives extracting logic.

If the error is in System.load itself then presumably libGDX catches that error and tries writing the natives somewhere else instead that is independant of the windows username.