Unciv: Do not load Discord if CPU ISA is not supported

Describe the bug Basically https://github.com/yairm210/Unciv/issues/1624 and https://github.com/yairm210/Unciv/issues/3283, also similar to https://github.com/yairm210/Unciv/issues/2361

When running on a CPU Instruction Set Architecture (or just a platform) not supported by Discord, loading the library fails, which crashes the process.

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'discord-rpc': Native library (linux-aarch64/libdiscord-rpc.so) not found in resource path (/app/data/Unciv.jar)
        at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:303)
	at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:427)
	at com.sun.jna.Library$Handler.<init>(Library.java:179)
	at com.sun.jna.Native.loadLibrary(Native.java:569)
	at com.sun.jna.Native.loadLibrary(Native.java:544)
	at club.minnced.discord.rpc.DiscordRPC.<clinit>(DiscordRPC.java:42)
	at com.unciv.app.desktop.DesktopLauncher.tryActivateDiscord(DesktopLauncher.kt:193)
	at com.unciv.app.desktop.DesktopLauncher.main(DesktopLauncher.kt:64)

The above is the output of the flatpak ran on a pinephone with postmarketos. The architecture is aarch64 in this case.

To Reproduce

  1. Run the game on some non-x86 platform
  2. Alternatively, you could run java in qemu (using pmbootstrap from postmarketos for instance), or delete the shared libraries from the jar to reproduce on a computer.

Expected behavior Discord is not loaded if it can’t be, but the game continues.

Additional context I had a look at the code. With all due respect, this is a terrible implementation 😃

https://github.com/yairm210/Unciv/blob/e0d7128bc627f725f94233af08545bc8ec79e7dd/desktop/src/com/unciv/app/desktop/RaspberryPiDetector.kt#L20-L22

This will only detect Raspbian (which I run on only one of the tens of ARM devices that I have at hand). For instance, it will not run on a raspberrypi running Archlinux, nor postmarketos/alpine/etc.

The issue here is that it won’t load a native library on the wrong microarchitecture. Instead of querying the OS name, the proper way would be to query the architecture (with os.arch it seems) and not load Discord if it is not part of the supported architectures (which are probably something like amd64 and i686/i386).

This will make it possible to run unciv on a lot of other architectures, from aarch64 (armv8), armv7, POWER, but also more esoteric things like RISC-V, Itanium, SPARC and whatnot 😃

Another possible implementation is to try to load discord, catch any errors, log them and continue as if nothing happened. This would be my favorite implementation, I think. I would also allow disabling discord from an environment variable for testing purposes, and those that don’t want to load Discord.

This is the section that would need a try/catch statement: https://github.com/yairm210/Unciv/blob/434136e6cc2d11b082c3937df9d0e15d0b87fcc3/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt#L63-L64

Catching exceptions can also future-proof the binary a bit against changing APIs and issues loading Discord.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Nice catch with the image

Ah no, sorry, the problem seems to be in a different place. The code there uses a native library load not ON A LINE OF CODE, as it were, but WHEN INITIALIZING THE STATIC VARIABLE which is “outside” the lines of code. A possible solution is to try and load that library ourselves, before accessing the static instance.

I hate Unciv hammering the network interface all the time in purely single player games anyway… I vote for 100% opt-in!

But - say - “disabling discord from an environment variable” - is that a feature of discord’s libraries? Or would we have to do that ourselves (in which case gameSettings.json might be the nicer place anyway - how to access that before the game is initialized is in the Android portrait code)?