[LWJGL/Slick] How do you distribute a game without JarSplice?

I’ve been wondering about this for a while.

I couldn’t find a way.

Do you guys know how to do it?

What do you mean by “without JarSplice”? Do you want to know what JarSplice does ‘in the background’?
You can create .jars that include a MANIFEST file inside of them which is something you could picture as a configuration file. In that file the Main class has to be documented, and then the java runtime is able to interpret your .jar as a runnable .jar and can start it :slight_smile:

I want to be able to distribute my game, without having to go through the task of using JarSplice. I’d want to just be able to export it and not have to use that darned program.

Eclipse --> Export

Really that’s it.

Export as “runnable jar”.
Or do you mean with natives?

Eclipse’s export handles natives fine. You can even pick your poison as to how they are packaged (or not) into the jar.

export with natives and everything so that it works without jarsplice.

I don’t know how to make myself more clear:

Using the little demo I did for Ray a couple days ago, make sure to use a correct launch configuration, and I’d say “Package required libraries” is the best option of the three, but you may have different goals.

This particular demo had no natives, but the process is identical (and works) with them, e.g. libGDX projects.

I know how to help. Here:
http://www.java-gaming.org/topics/compiling-and-running-a-lwjgl-project/31479/view.html

Eclipse doesn’t export with natives. Libgdx is a whole different story. It loads natives from a jar at runtime, so you don’t have to do anything about it. For Libgdx natives are like resources or something like that.

Yes it does. Not really. So does JarSplice and any app with natives. That’s kinda because they are.

/sass

K, so I made this: NativeLoader.jar

It’s based off the JarSplice code, and should settle this once and for all. I might do an actual release in the WIP/tools/etc board, but first could some people test it, make sure I didn’t do something stupid? I want this to be as idiot-proof as possible, so I may make some tweaks yet.

Just import the jar like any other into your eclipse project, and call NativeLoader.loadNatives() as the first thing in your main(). Worked like a charm with a slick app I tested.
It recognizes if you are running in eclipse, or in a exported jar, and acts accordingly.

Note: the nativesFolder param to loadNatives() is the folder you’re keeping natives-win.jar etc. in your eclipse project, e.g. /natives/ This directory does not have to be in the eclipse project, however that is the usual.
I used “Extract required libraries” when exporting, “packaging” doesn’t work, may be able to fix that yet.

I’ll answer any questions here or in PM until I get an actual thread for it. If you have an error, please report it to me with a stacktrace (have the debug flag on).

I also use a [icode]NativesLoader[/icode] for my engine I made for a local competition.


package com.shc.silenceengine.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import com.shc.silenceengine.exceptions.SilenceException;

public class NativeUtils
{
    // Temporary folder to store natives
    private static File tmp;
    
    public static void prepareLWJGLNatives()
    {
        try
        {
            tmp = File.createTempFile("Silence", "Engine");

            tmp.delete();
            tmp.mkdir();

            tmp.deleteOnExit();

            if (SilenceUtils.isWindows())
            {
                if (SilenceUtils.is64Bit())
                {
                    extractNative("lwjgl64.dll", tmp);
                    extractNative("OpenAL64.dll", tmp);
                    extractNative("jinput-dx8_64.dll", tmp);
                    extractNative("jinput-raw_64.dll", tmp);
                }
                else
                {
                    extractNative("lwjgl.dll", tmp);
                    extractNative("OpenAL32.dll", tmp);
                    extractNative("jinput-dx8.dll", tmp);
                    extractNative("jinput-raw.dll", tmp);
                }
            }
            else if (SilenceUtils.isLinux())
            {
                if (SilenceUtils.is64Bit())
                {
                    extractNative("liblwjgl64.so", tmp);
                    extractNative("libopenal64.so", tmp);
                    extractNative("libjinput-linux64.so", tmp);
                }
                else
                {
                    extractNative("liblwjgl.so", tmp);
                    extractNative("libopenal.so", tmp);
                    extractNative("libjinput-linux.so", tmp);
                }
            }
            else if (SilenceUtils.isMac())
            {
                extractNative("liblwjgl.jnilib", tmp);
                extractNative("openal.dylib", tmp);
                extractNative("libjinput-osx.jnilib", tmp);
            }
            else
            {
                throw new SilenceException("The Operating System you are using is not Supported by SilenceEngine.");
            }

            System.setProperty("org.lwjgl.librarypath", tmp.getAbsolutePath());
        }
        catch (Exception e)
        {
            throw new SilenceException(e.getMessage());
        }
    }

    private static void extractNative(String path, File dir)
    {
        InputStream is = NativeUtils.class.getClassLoader().getResourceAsStream("natives/" + path);

        String[] parts = ("natives/" + path).replaceAll("\\\\", "/").split("/");
        String filename = (parts.length > 1) ? parts[parts.length - 1] : null;

        try
        {
            File tmp = new File(dir, filename);
            tmp.deleteOnExit();
            FileOutputStream os = new FileOutputStream(tmp);

            byte[] buffer = new byte[1024];
            int readBytes;

            try
            {
                while ((readBytes = is.read(buffer)) != -1)
                {
                    os.write(buffer, 0, readBytes);
                }
            }
            finally
            {
                os.close();
                is.close();
            }
        }
        catch (Exception e)
        {
            throw new SilenceException(e.getMessage());
        }
    }
    
    public static void deleteNatives()
    {
        for (File f : tmp.listFiles())
        {
            f.delete();
        }
        
        tmp.delete();
    }
}

I just keep the natives in the [icode]natives/[/icode] folder in the JAR.