Exporting Java game using Jogl into ONLY one Jar in Eclipse

I tested my own suggestion and unforunately - as stated - it doesn’t work. After that I tried the method from the javalobby forum, that lhkbob posted and this does indeed work :slight_smile: It might be vendor-specific (sun vm only!?) and not future proof, but it should suffice for now.

Here is my working Launcher class (the Launcher might not be needed, but this way it is nicely separated and maybe I extend this to a generic wrapper):


import java.lang.reflect.Field;

/**
 *
 * @author cylab
 */
public class Launcher
{
    public static void main(String[] args)
    {
        try
        {
            // Get the system paths field, make it accessible and to null
            // so that whenever "System.loadLibrary" is called,
            // it will be reconstructed with the changed value.
            Field sys_paths = ClassLoader.class.getDeclaredField("sys_paths");
            sys_paths.setAccessible(true);
            sys_paths.set(ClassLoader.class, null);
            // Now change the System property
            System.setProperty("java.library.path", 
                "/home/cylab/.netbeans/6.5/jogl-runtime/jogl.jar-natives-linux-i586:/home/cylab/.netbeans/6.5/gluegen-runtime/gluegen-rt.jar-natives-linux-i586");

            // Get the reference to the actual app class after setting java.library.path and start your app
            Class.forName("org.yourorghere.SimpleJOGL")
                .getMethod("main", new Class[]{String[].class}).invoke(null, new Object[]{args});

        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

You will still need some code to get the right platform library path.

Looks interesting, I’ll try it now.

Good news everyone, it worked! Now we have a way of changing the java.library.path programatically from inside main(). Setting ClassLoader.class to null really did the trick. Thank you cylab!

Here’s my version of your code.


public class TheMainClass {
    
    public static void main(String[] args) {
        if (args.length==0) {
            try {
                Field sys_paths = ClassLoader.class
                        .getDeclaredField("sys_paths");
                sys_paths.setAccessible(true);
                sys_paths.set(ClassLoader.class, null);
                System.setProperty("java.library.path", "binaries/win32");
                String[] arguments = {"start"};
                TheMainClass.class.getMethod("main", String[].class)
                        .invoke(null, new Object[] {arguments});
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        } else {
            //do whatever main should really do here
        }
    }
}

If an exception occurs one can explain to the user that he can bypass this if he starts the game with the an argument (should he want to aquire the jogl binaries manually and place them in the java.library.path on his system).

As you can see this code makes it impossible to send arguments to the application, if that is needed the code needs to be rewritten a little. It’s easily done but I wanted to keep the code simple and clean for now, this way only one main() method is needed in the application.

What the code does is that it sets the java.library.path to “binaries\win32” - the “binaries” folder is in the same folder as the jar file and the “win32” folder is inside the “binaries” folder (duh).

Remember: If you change the class name from “TheMainClass” to something else you also have to change “TheMainClass” to the same thing a few rows down into the code.

This code was tested on Windows Vista 64, anyone else care to test on other systems? Some of you may notice that I’m loading the win32 binaries on a 64 bit operating system, I guess its the type of Java Virtual Machine that counts and not the OS, I have the 32bit VM installed.

By the way, “/” should be pretty universal right? Would be nice not having to use System.getProperty(“file.separator”) all the time.

Alright, great job everyone. :slight_smile: Now it’s just a matter of figuring out which binaries to use (and compress them if possible). Any suggestions?

You won’t need to call the main method again via reflection with the javalobby version. I just combined both approaches to get a separation of the launcher and the normal main class. If you don’t want that, you can simply use:


public class TheMainClass {
    
    public static void main(String[] args) {
        if (System.getProperty("suppress-natives-injection",null)==null) {
            try {
                Field sys_paths = ClassLoader.class
                        .getDeclaredField("sys_paths");
                sys_paths.setAccessible(true);
                sys_paths.set(ClassLoader.class, null);
                System.setProperty("java.library.path", "binaries/win32");
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        }
         //do whatever main should really do here
    }
}

This way you can still have normal arguments. On an exception you could advice the user to call the app with


java -Dsuppress-natives-injection -Djava.library.path=/users/own/natives/path YourMainClass

Why that’s just splendid! Nice to see that you don’t have to trick Java by calling main a second time in order to change “java.library.path”.

Now I’m (again) wondering if it’s possible to launch a java application from inside another java application (a solution that always works). Here’s why:

I was thinking about having one java application that asks the user what operating system he is on. Then he presses “start server” or “start client”, then another java application will be launched with arguments descibing which binaries to use. The point of having one java application launching another would be that if the game crashes the launcher application would still be running and can display messages etc about it.

The problem with using exec() would be, I guess, that some systems won’t have just “java” bound to the whole path to java.exe. I’ve seen that once on the University. There’s also something about allowing a java application to launch other java applications that screams security warning to me, making me guess that some places will not allow this thus making the game unable to start.

Thanks for all the help, I hope there’s a solution to this also.

I’ve been wondering by the way… do Jogl draw things outside the area defined by glOrtho? If I draw a circle, but half of it is outside the ortho area, is only the half showing drawn or is the rest also drawn? How about if the whole circle is outside the ortho area, is it not drawn automatically (the commands drawing the circle are ignored) or do I have to implement some kind of bounding box check myself to decide if the commands should be executed or not?

Not drawing stuff outside of view auomatically sounds too good to be true, but I might as well ask anyway. :wink:

The drawing command is not ignored, but nothing would be drawn onscreen (or half-circle etc.). When processing the drawing command, the opengl drivers will clip away things outside of the window. Even though it clips it, it’s better to cull it with the CPU since then the GL commands are never invoked.

Ok, that’s nice. Then I’ll have to somehow find out if the CPU saves processing power if I calculate if a object is worth drawing or not. I guess it’ll only be worth the calculations if very complex things are to be drawn.

Anybody have any thought about the other thing I was wondering about?

All these mechanisms apply only for content downloaded and then run with full privileges anyway, so no - starting a java app vie exec() won’t have security problems. To get the java[.exe] you can make yourself a search-list of known directories for the jvm installation, if the vm is not installed “correctly”.

While having a launcher app may be useful, I think you should try to find out operation system automatically. There are some System properties, that contain info about the OS and CPU platform. Don’t know them from the head now, just print them all out and look for something ending in .os, .arch and/or .platform…

Alright, very interesting. Good to know there won’t be any security problems; I’d hate to learn that my game is unplayable in some school somewhere just because the admins over there had disallowed java applications from launching other java applications, but if that’s not possible I don’t have to worry. :slight_smile:

I think I’ll go with a launcher application because then I could have it restart the server if it crashes or something. Wonder if it’s possible to close a started application (if Java was the one that started it)… I bet it is.

I’ll probably have automatic OS detection, however if the app is unable to determine correctly the user will be able to manually set his OS. Thanks for the input.

Now gentlemen it’s just a matter of being able to extract the DLL files from the jar archive. Anyone knows a good way?

JarFile javadoc… :stuck_out_tongue_winking_eye:

;_; Alright, I’ll google it myself… :wink:

Edit: Why hello there Mr. getInputStream, how’d you do?