Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save SingingBush/666bb482d564865b846580e22976f901 to your computer and use it in GitHub Desktop.
Save SingingBush/666bb482d564865b846580e22976f901 to your computer and use it in GitHub Desktop.
A short story about the difficulties in using unmaintained software (jEnesis)
Today I did a quick google search to see if any emulators had been written in Java. As it urns out there was a Sega Megadrive emulator called [jEnesis](http://www.workingdesign.de/projects/jenesis.php) that was written by Stephan Dittrich and released back in 2006.
Most of the site is just dead links now and I wasn't able to find a working download there but I was able to track down a build of the project else where. Unfortunately however, the build I found was version 0.0.5 from May 2006 so it doesn't include the changes that went into the final v0.1.0 that was supposed to have been built in June 2006 (perhaps it was never made public).
The jEnesis.jar that I downloaded depends on a very old [lwjgl](https://www.lwjgl.org/). The timestamp for the file was December 2005 which would make it [version 0.99](https://sourceforge.net/projects/java-game-lib/files/Official%20Releases/LWJGL%200.99/).
This old lwjgl only supported 32-bit systems, so running `java -cp jEnesis.jar;lwjgl.jar jenesis.Main` would throw an exception informing me that _lwjgl.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform_ and it would be the same if I updated to lwjgl 1.1.4.
In fact, I'd have to make the transition to lwjgl 2 before seeing the application boot up.
```bash
java -cp jEnesis.jar;lwjgl-2.9.3\jar\lwjgl.jar -Djava.library.path=lwjgl-2.9.3\native\windows jenesis.Main
```
At this stage I was feeling pretty positive about this old project still being usable. On opening a rom file though I saw the following stack trace:
```bash
java.lang.RuntimeException: No OpenGL context found in the current thread.
at org.lwjgl.opengl.GLContext.getCapabilities(GLContext.java:124)
at org.lwjgl.opengl.GL11.glViewport(GL11.java:3261)
at a.b.c.a(Unknown Source)
at jenesis.video.glScreen.do(Unknown Source)
at jenesis.a.void(Unknown Source)
at jenesis.ui.JenesisAppFrame$2.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
```
A quick google search and reading some Stack Overflow posts revealed that the way in which jEnesis was using lwjgl to setup OpenGL was not quite right.
By now I've become to invested in the task to simply quit. I decide to try using _jEnesis.jar_ as a dependency by creating a Java project and using Mavens's system scope to conveniently put it into my project along with lwjgl and slf4j:
```xml
<dependency>
<groupId>jenesis</groupId>
<artifactId>jenesis</artifactId>
<version>0.0.5</version>
<scope>system</scope>
<systemPath>${basedir}/lib/jEnesis.jar</systemPath>
</dependency>
```
At first this approach seemed like it would be fine. The main entry point for jEnesis simply created an instance of the `jenesis.ui.JenesisAppFrame` class so I started digging around from there using Intellij's inbuilt decompiler. It quickly became apparent that the author had used a tool such as [ProGuard](https://sourceforge.net/projects/proguard/) which obfuscates the code during the build process as variables and method names had all been renamed to either single characters or reserved words.
*Interesting fact*; The JVM can happily run with code such as `int int = 4096;` because byte code allows keywords to be used as identifiers, it's just javac that will prevent you using them in Java source code.
Not only has _jEnesis.jar_ had all its identifiers mangled but classes and methods all over the place have been made final so even using inheritance create a work around for the problem isn't possible.
My next tactic was to try using various Java decompilers in an attempt to get some working source files as a starting point with which to refactor and eventually fix this old project. [CFR - another java decompiler](http://www.benf.org/other/cfr/) seemed like a good option. It's website may be plain but change history showed that the maintainer has been putting in improvements regularly since 2013 with it's most recent release only a few days ago. Running `java -jar cfr-0.138.jar jEnesis.jar --outputdir jenesis-src --renameillegalidents true` gave me the decompiled classes in a format that was still ugly but at least renamed identifiers that used keywords, unfortunately it still wasn't enough to generate working source code. The next option was [Java Decompiler](http://jd.benow.ca/), specifically [JD_GUI v1.4.0](https://github.com/java-decompiler/jd-gui), like CFR, this decompiler also worked arounf the keyword issue but was not able to producing working source code. It was the same problem for [Luyten](https://github.com/deathmarine/Luyten/), I downloaded the latest version (v0.5.3) but it was unable to provide working source files. I even tried using Intellij's built in Fernflower decompiler directly from the command line (yes this is also possible) by using the jar for the decompiler plugin which is located `<Intellij base directory>\plugins\java-decompiler\lib\java-decompiler.jar`. To use it just run:
```bash
java -cp java-decompiler.jar org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler jEnesis.jar outputDirectory
```
Out of the lot of them CFR seemed to do the best job but none of them were able to produce source that could actually compile. To give an idea of the problem, here's a list of some of the classes that are within the jar:
```
a.a.a
a.a.b
a.b.a
a.b.b
a.b.c
a.b.d
a.c.a
a.c.b
... etc etc
```
So not only do you have various packages in which there is a class called _a_ but there's also the possibility for a method to be called _a_ or a variable to be named _a_ and so on. So sooner or later all of the decompilers produced source that was confused about which types it was using.
By this time I'm a few hours in to what I thought would be short distraction from daily life. So I'm going to give up on jEnesis for now. It's not been as waste of time though as I've found out a few interesting things along the way. It's a real shame that projects such as jEnesis will probably never be used again though, this is a good example of why developers should publish source code to public repositories such as [GitHub](https://github.com), [Bitbucket](http://bitbucket.org) and [GitLab](https://gitlab.com/).
So please Stephan, if you come across this, consider publishing the jEnesis source code under the [GPL](https://opensource.org/licenses/gpl-license).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment